nvapi/
gpu.rs

1use std::{ptr, fmt};
2use void::{Void, ResultVoidExt};
3use sys::gpu::{self, pstate, clock, power, cooler, thermal, display};
4use sys::{self, driverapi, i2c};
5use types::{Kibibytes, KilohertzDelta, Kilohertz2Delta, Microvolts, Percentage, Percentage1000, RawConversion};
6use thermal::CoolerLevel;
7use clock::{ClockDomain, VfpMask};
8use pstate::PState;
9
10#[derive(Debug)]
11pub struct PhysicalGpu(sys::handles::NvPhysicalGpuHandle);
12
13unsafe impl Send for PhysicalGpu { }
14
15pub use sys::gpu::{SystemType, PerformanceDecreaseReason};
16pub use sys::gpu::private::{RamType, RamMaker, Foundry, VendorId as Vendor};
17pub use sys::gpu::clock::ClockFrequencyType;
18pub use sys::gpu::display::{ConnectedIdsFlags, DisplayIdsFlags, MonitorConnectorType};
19pub type ClockFrequencies = <sys::gpu::clock::NV_GPU_CLOCK_FREQUENCIES as RawConversion>::Target;
20pub type Utilizations = <pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX as RawConversion>::Target;
21
22impl PhysicalGpu {
23    pub fn handle(&self) -> &sys::handles::NvPhysicalGpuHandle {
24        &self.0
25    }
26
27    pub fn enumerate() -> sys::Result<Vec<Self>> {
28        trace!("gpu.enumerate()");
29        let mut handles = [Default::default(); sys::types::NVAPI_MAX_PHYSICAL_GPUS];
30        let mut len = 0;
31        match unsafe { gpu::NvAPI_EnumPhysicalGPUs(&mut handles, &mut len) } {
32            sys::status::NVAPI_NVIDIA_DEVICE_NOT_FOUND => Ok(Vec::new()),
33            status => sys::status_result(status).map(move |_| handles[..len as usize].iter().cloned().map(PhysicalGpu).collect()),
34        }
35    }
36
37    pub fn tachometer(&self) -> sys::Result<u32> {
38        trace!("gpu.tachometer()");
39        let mut out = 0;
40        unsafe {
41            sys::status_result(cooler::NvAPI_GPU_GetTachReading(self.0, &mut out))
42                .map(move |_| out)
43        }
44    }
45
46    pub fn short_name(&self) -> sys::Result<String> {
47        trace!("gpu.short_name()");
48        let mut str = sys::types::short_string();
49        unsafe {
50            sys::status_result(gpu::private::NvAPI_GPU_GetShortName(self.0, &mut str))
51                .map(|_| str.convert_raw().void_unwrap())
52        }
53    }
54
55    pub fn full_name(&self) -> sys::Result<String> {
56        trace!("gpu.full_name()");
57        let mut str = sys::types::short_string();
58        unsafe {
59            sys::status_result(gpu::NvAPI_GPU_GetFullName(self.0, &mut str))
60                .map(|_| str.convert_raw().void_unwrap())
61        }
62    }
63
64    pub fn vbios_version_string(&self) -> sys::Result<String> {
65        trace!("gpu.vbios_version_string()");
66        let mut str = sys::types::short_string();
67        unsafe {
68            sys::status_result(gpu::NvAPI_GPU_GetVbiosVersionString(self.0, &mut str))
69                .map(|_| str.convert_raw().void_unwrap())
70        }
71    }
72
73    pub fn driver_model(&self) -> sys::Result<DriverModel> {
74        trace!("gpu.driver_model()");
75        let mut value = 0;
76        unsafe {
77            sys::status_result(gpu::private::NvAPI_GetDriverModel(self.0, &mut value))
78                .map(|_| DriverModel::new(value))
79        }
80    }
81
82    pub fn gpu_id(&self) -> sys::Result<u32> {
83        trace!("gpu.gpu_id()");
84        let mut value = 0;
85        unsafe {
86            sys::status_result(gpu::private::NvAPI_GetGPUIDFromPhysicalGPU(self.0, &mut value))
87                .map(|_| value)
88        }
89    }
90
91    pub fn pci_identifiers(&self) -> sys::Result<PciIdentifiers> {
92        trace!("gpu.pci_identifiers()");
93        let mut pci = PciIdentifiers::default();
94        unsafe {
95            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))
96                .map(|_| pci)
97        }
98    }
99
100    pub fn board_number(&self) -> sys::Result<[u8; 0x10]> {
101        trace!("gpu.board_number()");
102        let mut data = gpu::NV_BOARD_INFO::zeroed();
103        data.version = gpu::NV_BOARD_INFO_VER;
104        unsafe {
105            sys::status_result(gpu::NvAPI_GPU_GetBoardInfo(self.0, &mut data))
106                .map(|_| data.BoardNum)
107        }
108    }
109
110    pub fn system_type(&self) -> sys::Result<SystemType> {
111        trace!("gpu.system_type()");
112        let mut ty = gpu::NV_SYSTEM_TYPE_UNKNOWN;
113        unsafe {
114            sys::status_result(gpu::NvAPI_GPU_GetSystemType(self.0, &mut ty))
115                .and_then(|_| gpu::SystemType::from_raw(ty).map_err(From::from))
116        }
117    }
118
119    pub fn core_count(&self) -> sys::Result<u32> {
120        trace!("gpu.core_count()");
121        let mut value = 0;
122        unsafe {
123            sys::status_result(gpu::NvAPI_GPU_GetGpuCoreCount(self.0, &mut value))
124                .map(|_| value)
125        }
126    }
127
128    pub fn shader_pipe_count(&self) -> sys::Result<u32> {
129        trace!("gpu.shader_pipe_count()");
130        let mut value = 0;
131        unsafe {
132            sys::status_result(gpu::private::NvAPI_GPU_GetShaderPipeCount(self.0, &mut value))
133                .map(|_| value)
134        }
135    }
136
137    pub fn shader_sub_pipe_count(&self) -> sys::Result<u32> {
138        trace!("gpu.shader_sub_pipe_count()");
139        let mut value = 0;
140        unsafe {
141            sys::status_result(gpu::NvAPI_GPU_GetShaderSubPipeCount(self.0, &mut value))
142                .map(|_| value)
143        }
144    }
145
146    pub fn ram_type(&self) -> sys::Result<RamType> {
147        trace!("gpu.ram_type()");
148        let mut value = gpu::private::NV_GPU_RAM_UNKNOWN;
149        unsafe {
150            sys::status_result(gpu::private::NvAPI_GPU_GetRamType(self.0, &mut value))
151                .and_then(|_| gpu::private::RamType::from_raw(value).map_err(From::from))
152        }
153    }
154
155    pub fn ram_maker(&self) -> sys::Result<RamMaker> {
156        trace!("gpu.ram_maker()");
157        let mut value = gpu::private::NV_GPU_RAM_MAKER_UNKNOWN;
158        unsafe {
159            sys::status_result(gpu::private::NvAPI_GPU_GetRamMaker(self.0, &mut value))
160                .and_then(|_| gpu::private::RamMaker::from_raw(value).map_err(From::from))
161        }
162    }
163
164    pub fn ram_bus_width(&self) -> sys::Result<u32> {
165        trace!("gpu.ram_bus_width()");
166        let mut value = 0;
167        unsafe {
168            sys::status_result(gpu::private::NvAPI_GPU_GetRamBusWidth(self.0, &mut value))
169                .map(|_| value)
170        }
171    }
172
173    pub fn ram_bank_count(&self) -> sys::Result<u32> {
174        trace!("gpu.ram_bank_count()");
175        let mut value = 0;
176        unsafe {
177            sys::status_result(gpu::private::NvAPI_GPU_GetRamBankCount(self.0, &mut value))
178                .map(|_| value)
179        }
180    }
181
182    pub fn ram_partition_count(&self) -> sys::Result<u32> {
183        trace!("gpu.ram_partition_count()");
184        let mut value = 0;
185        unsafe {
186            sys::status_result(gpu::private::NvAPI_GPU_GetPartitionCount(self.0, &mut value))
187                .map(|_| value)
188        }
189    }
190
191    pub fn foundry(&self) -> sys::Result<Foundry> {
192        trace!("gpu.foundry()");
193        let mut value = gpu::private::NV_GPU_FOUNDRY_UNKNOWN;
194        unsafe {
195            sys::status_result(gpu::private::NvAPI_GPU_GetFoundry(self.0, &mut value))
196                .and_then(|_| gpu::private::Foundry::from_raw(value).map_err(From::from))
197        }
198    }
199
200    pub fn memory_info(&self) -> sys::Result<MemoryInfo> {
201        trace!("gpu.memory_info()");
202        let mut data = driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO::zeroed();
203        data.version = driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO_VER;
204
205        sys::status_result(unsafe { driverapi::NvAPI_GPU_GetMemoryInfo(self.0, &mut data) })
206            .map(|_| data.convert_raw().void_unwrap())
207    }
208
209    pub fn clock_frequencies(&self, clock_type: ClockFrequencyType) -> sys::Result<ClockFrequencies> {
210        trace!("gpu.clock_frequencies({:?})", clock_type);
211        let mut clocks = clock::NV_GPU_CLOCK_FREQUENCIES::zeroed();
212        clocks.version = clock::NV_GPU_CLOCK_FREQUENCIES_VER;
213        clocks.set_ClockType(clock_type.raw());
214
215        sys::status_result(unsafe { clock::NvAPI_GPU_GetAllClockFrequencies(self.0, &mut clocks) })
216            .map(|_| clocks.convert_raw().void_unwrap())
217    }
218
219    pub fn current_pstate(&self) -> sys::Result<::pstate::PState> {
220        trace!("gpu.current_pstate()");
221        let mut pstate = 0;
222
223        sys::status_result(unsafe { pstate::NvAPI_GPU_GetCurrentPstate(self.0, &mut pstate) })?;
224
225        ::pstate::PState::from_raw(pstate).map_err(From::from)
226    }
227
228    pub fn pstates(&self) -> sys::Result<<pstate::NV_GPU_PERF_PSTATES20_INFO as RawConversion>::Target> {
229        trace!("gpu.pstates()");
230        let mut info = pstate::NV_GPU_PERF_PSTATES20_INFO::zeroed();
231        info.version = pstate::NV_GPU_PERF_PSTATES20_INFO_VER;
232
233        sys::status_result(unsafe { pstate::NvAPI_GPU_GetPstates20(self.0, &mut info) })
234            .and_then(|_| info.convert_raw().map_err(From::from))
235    }
236
237    pub fn set_pstates<I: Iterator<Item=(PState, ClockDomain, KilohertzDelta)>>(&self, deltas: I) -> sys::Result<()> {
238        trace!("gpu.set_pstates()");
239        use std::collections::BTreeMap;
240
241        let mut info = pstate::NV_GPU_PERF_PSTATES20_INFO::zeroed();
242        info.version = pstate::NV_GPU_PERF_PSTATES20_INFO_VER;
243
244        let mut map: BTreeMap<PState, (usize, usize)> = Default::default();
245        for (pstate, clock, delta) in deltas {
246            trace!("gpu.set_pstate({:?}, {:?}, {:?})", pstate, clock, delta);
247            let pstates = map.len();
248            let map = map.entry(pstate).or_insert((pstates, 0));
249            let entry = &mut info.pstates[map.0];
250            entry.pstateId = pstate.raw();
251            let entry = &mut entry.clocks[map.1];
252            entry.domainId = clock.raw();
253            entry.freqDelta_kHz.value = delta.0;
254            map.1 += 1;
255        }
256        info.numPstates = map.len() as _;
257        info.numClocks = map.iter().map(|v| (v.1).1).max().unwrap_or(0) as _;
258
259        sys::status_result(unsafe { pstate::private::NvAPI_GPU_SetPstates20(self.0, &info) })
260    }
261
262    pub fn dynamic_pstates_info(&self) -> sys::Result<Utilizations> {
263        trace!("gpu.dynamic_pstates_info()");
264        let mut info = pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX::zeroed();
265        info.version = pstate::NV_GPU_DYNAMIC_PSTATES_INFO_EX_VER;
266
267        sys::status_result(unsafe { pstate::NvAPI_GPU_GetDynamicPstatesInfoEx(self.0, &mut info) })
268            .and_then(|_| info.convert_raw().map_err(From::from))
269    }
270
271    /// Private and deprecated, use `dynamic_pstates_info()` instead.
272    pub fn usages(&self) -> sys::Result<<clock::private::NV_USAGES_INFO as RawConversion>::Target> {
273        trace!("gpu.usages()");
274        let mut usages = clock::private::NV_USAGES_INFO::zeroed();
275        usages.version = clock::private::NV_USAGES_INFO_VER;
276
277        sys::status_result(unsafe { clock::private::NvAPI_GPU_GetUsages(self.0, &mut usages) })
278            .and_then(|_| usages.convert_raw().map_err(From::from))
279    }
280
281    pub fn vfp_mask(&self) -> sys::Result<<clock::private::NV_CLOCK_MASKS as RawConversion>::Target> {
282        trace!("gpu.vfp_mask()");
283        let mut data = clock::private::NV_CLOCK_MASKS::zeroed();
284        data.version = clock::private::NV_CLOCK_MASKS_VER;
285
286        sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostMask(self.0, &mut data) })
287            .and_then(|_| data.convert_raw().map_err(From::from))
288    }
289
290    pub fn vfp_table(&self, mask: [u32; 4]) -> sys::Result<<clock::private::NV_CLOCK_TABLE as RawConversion>::Target> {
291        trace!("gpu.vfp_table({:?})", mask);
292        let mut data = clock::private::NV_CLOCK_TABLE::zeroed();
293        data.version = clock::private::NV_CLOCK_TABLE_VER;
294        data.mask = mask;
295
296        sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostTable(self.0, &mut data) })
297            .and_then(|_| data.convert_raw().map_err(From::from))
298    }
299
300    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<()> {
301        trace!("gpu.set_vfp_table({:?})", mask);
302        let mut data = clock::private::NV_CLOCK_TABLE::zeroed();
303        data.version = clock::private::NV_CLOCK_TABLE_VER;
304        data.mask = mask;
305        for (i, delta) in clocks {
306            trace!("gpu.set_vfp_table({:?}, {:?})", i, delta);
307            data.gpuDeltas[i].freqDeltaKHz = delta.0;
308            VfpMask::set_bit(&mut data.mask, i);
309        }
310        for (i, delta) in memory {
311            data.memFilled[i] = 1;
312            data.memDeltas[i] = delta.0;
313        }
314
315        sys::status_result(unsafe { clock::private::NvAPI_GPU_SetClockBoostTable(self.0, &data) })
316    }
317
318    pub fn vfp_ranges(&self) -> sys::Result<<clock::private::NV_CLOCK_RANGES as RawConversion>::Target> {
319        trace!("gpu.vfp_ranges()");
320        let mut data = clock::private::NV_CLOCK_RANGES::zeroed();
321        data.version = clock::private::NV_CLOCK_RANGES_VER;
322
323        sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostRanges(self.0, &mut data) })
324            .and_then(|_| data.convert_raw().map_err(From::from))
325    }
326
327    pub fn vfp_locks(&self) -> sys::Result<<clock::private::NV_CLOCK_LOCK as RawConversion>::Target> {
328        trace!("gpu.vfp_locks()");
329        let mut data = clock::private::NV_CLOCK_LOCK::zeroed();
330        data.version = clock::private::NV_CLOCK_LOCK_VER;
331
332        sys::status_result(unsafe { clock::private::NvAPI_GPU_GetClockBoostLock(self.0, &mut data) })
333            .and_then(|_| data.convert_raw().map_err(From::from))
334    }
335
336    pub fn set_vfp_locks<I: Iterator<Item=(usize, Option<Microvolts>)>>(&self, values: I) -> sys::Result<()> {
337        trace!("gpu.set_vfp_locks()");
338        use clock::ClockLockMode;
339
340        let mut data = clock::private::NV_CLOCK_LOCK::zeroed();
341        data.version = clock::private::NV_CLOCK_LOCK_VER;
342        for (i, (id, voltage)) in values.enumerate() {
343            trace!("gpu.set_vfp_lock({:?}, {:?})", id, voltage);
344            data.count += 1;
345            let entry = &mut data.entries[i];
346            entry.id = id as _;
347            if let Some(voltage) = voltage {
348                entry.mode = ClockLockMode::Manual.raw();
349                entry.voltage_uV = voltage.0;
350            } else {
351                // these are already 0
352                //entry.mode = ClockLockMode::None.raw();
353                //entry.voltage_uV = 0;
354            }
355        }
356
357        sys::status_result(unsafe { clock::private::NvAPI_GPU_SetClockBoostLock(self.0, &data) })
358    }
359
360    pub fn vfp_curve(&self, mask: [u32; 4]) -> sys::Result<<power::private::NV_VFP_CURVE as RawConversion>::Target> {
361        trace!("gpu.vfp_curve({:?})", mask);
362        let mut data = power::private::NV_VFP_CURVE::zeroed();
363        data.version = power::private::NV_VFP_CURVE_VER;
364        data.mask = mask;
365
366        sys::status_result(unsafe { power::private::NvAPI_GPU_GetVFPCurve(self.0, &mut data) })
367            .and_then(|_| data.convert_raw().map_err(From::from))
368    }
369
370    pub fn core_voltage(&self) -> sys::Result<<power::private::NV_VOLTAGE_STATUS as RawConversion>::Target> {
371        trace!("gpu.core_voltage()");
372        let mut data = power::private::NV_VOLTAGE_STATUS::zeroed();
373        data.version = power::private::NV_VOLTAGE_STATUS_VER;
374
375        sys::status_result(unsafe { power::private::NvAPI_GPU_GetCurrentVoltage(self.0, &mut data) })
376            .and_then(|_| data.convert_raw().map_err(From::from))
377    }
378
379    pub fn core_voltage_boost(&self) -> sys::Result<<power::private::NV_VOLTAGE_BOOST_PERCENT as RawConversion>::Target> {
380        trace!("gpu.core_voltage_boost()");
381        let mut data = power::private::NV_VOLTAGE_BOOST_PERCENT::zeroed();
382        data.version = power::private::NV_VOLTAGE_BOOST_PERCENT_VER;
383
384        sys::status_result(unsafe { power::private::NvAPI_GPU_GetCoreVoltageBoostPercent(self.0, &mut data) })
385            .and_then(|_| data.convert_raw().map_err(From::from))
386    }
387
388    pub fn set_core_voltage_boost(&self, value: Percentage) -> sys::Result<()> {
389        trace!("gpu.set_core_voltage_boost({:?})", value);
390        let mut data = power::private::NV_VOLTAGE_BOOST_PERCENT::zeroed();
391        data.version = power::private::NV_VOLTAGE_BOOST_PERCENT_VER;
392        data.percent = value.0;
393
394        sys::status_result(unsafe { power::private::NvAPI_GPU_SetCoreVoltageBoostPercent(self.0, &data) })
395    }
396
397    pub fn power_usage(&self) -> sys::Result<<power::private::NV_GPU_POWER_TOPO as RawConversion>::Target> {
398        trace!("gpu.power_usage()");
399        let mut data = power::private::NV_GPU_POWER_TOPO::zeroed();
400        data.version = power::private::NV_GPU_POWER_TOPO_VER;
401
402        sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerTopologyGetStatus(self.0, &mut data) })
403            .and_then(|_| data.convert_raw().map_err(From::from))
404    }
405
406    pub fn power_limit_info(&self) -> sys::Result<<power::private::NV_GPU_POWER_INFO as RawConversion>::Target> {
407        trace!("gpu.power_limit_info()");
408        let mut data = power::private::NV_GPU_POWER_INFO::zeroed();
409        data.version = power::private::NV_GPU_POWER_INFO_VER;
410
411        sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesGetInfo(self.0, &mut data) })
412            .and_then(|_| data.convert_raw().map_err(From::from))
413    }
414
415    pub fn power_limit(&self) -> sys::Result<<power::private::NV_GPU_POWER_STATUS as RawConversion>::Target> {
416        trace!("gpu.power_limit()");
417        let mut data = power::private::NV_GPU_POWER_STATUS::zeroed();
418        data.version = power::private::NV_GPU_POWER_STATUS_VER;
419
420        sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesGetStatus(self.0, &mut data) })
421            .and_then(|_| data.convert_raw().map_err(From::from))
422    }
423
424    pub fn set_power_limit<I: Iterator<Item=Percentage1000>>(&self, values: I) -> sys::Result<()> {
425        trace!("gpu.set_power_limit()");
426        let mut data = power::private::NV_GPU_POWER_STATUS::zeroed();
427        data.version = power::private::NV_GPU_POWER_STATUS_VER;
428        //data.valid = 1;
429        for (entry, v) in data.entries.iter_mut().zip(values) {
430            trace!("gpu.set_power_limit({:?})", v);
431            entry.power = v.0;
432            data.count += 1;
433        }
434
435        sys::status_result(unsafe { power::private::NvAPI_GPU_ClientPowerPoliciesSetStatus(self.0, &data) })
436    }
437
438    pub fn thermal_settings(&self, index: Option<u32>) -> sys::Result<<thermal::NV_GPU_THERMAL_SETTINGS as RawConversion>::Target> {
439        trace!("gpu.thermal_settings({:?})", index);
440        let mut data = thermal::NV_GPU_THERMAL_SETTINGS::zeroed();
441        data.version = thermal::NV_GPU_THERMAL_SETTINGS_VER;
442
443        sys::status_result(unsafe { thermal::NvAPI_GPU_GetThermalSettings(self.0, index.unwrap_or(thermal::NVAPI_THERMAL_TARGET_ALL as _), &mut data) })
444            .and_then(|_| data.convert_raw().map_err(From::from))
445    }
446
447    pub fn thermal_limit_info(&self) -> sys::Result<<thermal::private::NV_GPU_THERMAL_INFO as RawConversion>::Target> {
448        trace!("gpu.thermal_limit_info()");
449        let mut data = thermal::private::NV_GPU_THERMAL_INFO::zeroed();
450        data.version = thermal::private::NV_GPU_THERMAL_INFO_VER;
451
452        sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesGetInfo(self.0, &mut data) })
453            .and_then(|_| data.convert_raw().map_err(From::from))
454    }
455
456    pub fn thermal_limit(&self) -> sys::Result<<thermal::private::NV_GPU_THERMAL_LIMIT as RawConversion>::Target> {
457        trace!("gpu.thermal_limit()");
458        let mut data = thermal::private::NV_GPU_THERMAL_LIMIT::zeroed();
459        data.version = thermal::private::NV_GPU_THERMAL_LIMIT_VER;
460
461        sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesGetLimit(self.0, &mut data) })
462            .and_then(|_| data.convert_raw().map_err(From::from))
463    }
464
465    pub fn set_thermal_limit<I: Iterator<Item=::thermal::ThermalLimit>>(&self, value: I) -> sys::Result<()> {
466        trace!("gpu.set_thermal_limit()");
467        let mut data = thermal::private::NV_GPU_THERMAL_LIMIT::zeroed();
468        data.version = thermal::private::NV_GPU_THERMAL_LIMIT_VER;
469        for (entry, v) in data.entries.iter_mut().zip(value) {
470            trace!("gpu.set_thermal_limit({:?})", v);
471            entry.controller = v.controller.raw();
472            entry.value = v.value.0 as _;
473            entry.flags = v.flags;
474            data.flags += 1;
475        }
476
477        sys::status_result(unsafe { thermal::private::NvAPI_GPU_ClientThermalPoliciesSetLimit(self.0, &data) })
478    }
479
480    pub fn cooler_settings(&self, index: Option<u32>) -> sys::Result<<cooler::private::NV_GPU_COOLER_SETTINGS as RawConversion>::Target> {
481        trace!("gpu.cooler_settings({:?})", index);
482        let mut data = cooler::private::NV_GPU_COOLER_SETTINGS::zeroed();
483        data.version = cooler::private::NV_GPU_COOLER_SETTINGS_VER;
484
485        sys::status_result(unsafe { cooler::private::NvAPI_GPU_GetCoolerSettings(self.0, index.unwrap_or(cooler::private::NVAPI_COOLER_TARGET_ALL as _), &mut data) })
486            .and_then(|_| data.convert_raw().map_err(From::from))
487    }
488
489    pub fn set_cooler_levels<I: Iterator<Item=CoolerLevel>>(&self, index: Option<u32>, values: I) -> sys::Result<()> {
490        trace!("gpu.set_cooler_levels({:?})", index);
491        let mut data = cooler::private::NV_GPU_SETCOOLER_LEVEL::zeroed();
492        data.version = cooler::private::NV_GPU_SETCOOLER_LEVEL_VER;
493        for (entry, level) in data.cooler.iter_mut().zip(values) {
494            trace!("gpu.set_cooler_level({:?})", level);
495            entry.currentLevel = level.level.0;
496            entry.currentPolicy = level.policy.raw();
497        }
498
499        sys::status_result(unsafe { cooler::private::NvAPI_GPU_SetCoolerLevels(self.0, index.unwrap_or(cooler::private::NVAPI_COOLER_TARGET_ALL as _), &mut data) })
500    }
501
502    pub fn restore_cooler_settings(&self, index: &[u32]) -> sys::Result<()> {
503        trace!("gpu.restore_cooler_settings({:?})", index);
504        let ptr = if index.is_empty() { ptr::null() } else { index.as_ptr() };
505        sys::status_result(unsafe { cooler::private::NvAPI_GPU_RestoreCoolerSettings(self.0, ptr, index.len() as u32) })
506    }
507
508    pub fn cooler_policy_table(&self, index: u32, policy: ::thermal::CoolerPolicy) -> sys::Result<<cooler::private::NV_GPU_COOLER_POLICY_TABLE as RawConversion>::Target> {
509        trace!("gpu.cooler_policy_table({:?})", index);
510        let mut data = cooler::private::NV_GPU_COOLER_POLICY_TABLE::zeroed();
511        data.version = cooler::private::NV_GPU_COOLER_POLICY_TABLE_VER;
512        data.policy = policy.raw();
513        let mut count = 0;
514
515        sys::status_result(unsafe { cooler::private::NvAPI_GPU_GetCoolerPolicyTable(self.0, index, &mut data, &mut count) })
516            .and_then(|_| data.convert_raw().map_err(From::from)).map(|mut c| {
517                c.levels.truncate(count as usize);
518                // TODO: ensure remaining levels are null?
519                c
520            })
521    }
522
523    pub fn set_cooler_policy_table(&self, index: u32, value: &<cooler::private::NV_GPU_COOLER_POLICY_TABLE as RawConversion>::Target) -> sys::Result<()> {
524        trace!("gpu.set_cooler_policy_table({:?}, {:?})", index, value);
525        let mut data = cooler::private::NV_GPU_COOLER_POLICY_TABLE::zeroed();
526        data.version = cooler::private::NV_GPU_COOLER_POLICY_TABLE_VER;
527
528        sys::status_result(unsafe { cooler::private::NvAPI_GPU_SetCoolerPolicyTable(self.0, index, &data, value.levels.len() as u32) })
529    }
530
531    pub fn restore_cooler_policy_table(&self, index: &[u32], policy: ::thermal::CoolerPolicy) -> sys::Result<()> {
532        trace!("gpu.restore_cooler_policy_table({:?}, {:?})", index, policy);
533        let ptr = if index.is_empty() { ptr::null() } else { index.as_ptr() };
534        sys::status_result(unsafe { cooler::private::NvAPI_GPU_RestoreCoolerPolicyTable(self.0, ptr, index.len() as u32, policy.raw()) })
535    }
536
537    pub fn perf_info(&self) -> sys::Result<<power::private::NV_GPU_PERF_INFO as RawConversion>::Target> {
538        trace!("gpu.perf_info()");
539        let mut data = power::private::NV_GPU_PERF_INFO::zeroed();
540        data.version = power::private::NV_GPU_PERF_INFO_VER;
541
542        sys::status_result(unsafe { power::private::NvAPI_GPU_PerfPoliciesGetInfo(self.0, &mut data) })
543            .and_then(|_| data.convert_raw().map_err(From::from))
544    }
545
546    pub fn perf_status(&self) -> sys::Result<<power::private::NV_GPU_PERF_STATUS as RawConversion>::Target> {
547        trace!("gpu.perf_status()");
548        let mut data = power::private::NV_GPU_PERF_STATUS::zeroed();
549        data.version = power::private::NV_GPU_PERF_STATUS_VER;
550
551        sys::status_result(unsafe { power::private::NvAPI_GPU_PerfPoliciesGetStatus(self.0, &mut data) })
552            .and_then(|_| data.convert_raw().map_err(From::from))
553    }
554
555    pub fn voltage_domains_status(&self) -> sys::Result<<power::private::NV_VOLT_STATUS as RawConversion>::Target> {
556        trace!("gpu.voltage_domains_status()");
557        let mut data = power::private::NV_VOLT_STATUS::zeroed();
558        data.version = power::private::NV_VOLT_STATUS_VER;
559
560        sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltageDomainsStatus(self.0, &mut data) })
561            .and_then(|_| data.convert_raw().map_err(From::from))
562    }
563
564    pub fn voltage_step(&self) -> sys::Result<<power::private::NV_VOLT_STATUS as RawConversion>::Target> {
565        trace!("gpu.voltage_step()");
566        let mut data = power::private::NV_VOLT_STATUS::zeroed();
567        data.version = power::private::NV_VOLT_STATUS_VER;
568
569        sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltageStep(self.0, &mut data) })
570            .and_then(|_| data.convert_raw().map_err(From::from))
571    }
572
573    pub fn voltage_table(&self) -> sys::Result<<power::private::NV_VOLT_TABLE as RawConversion>::Target> {
574        trace!("gpu.voltage_table()");
575        let mut data = power::private::NV_VOLT_TABLE::zeroed();
576        data.version = power::private::NV_VOLT_TABLE_VER;
577
578        sys::status_result(unsafe { power::private::NvAPI_GPU_GetVoltages(self.0, &mut data) })
579            .and_then(|_| data.convert_raw().map_err(From::from))
580    }
581
582    pub fn performance_decrease(&self) -> sys::Result<PerformanceDecreaseReason> {
583        trace!("gpu.performance_decrease()");
584
585        let mut data = gpu::NV_GPU_PERF_DECREASE_NONE;
586
587        sys::status_result(unsafe { gpu::NvAPI_GPU_GetPerfDecreaseInfo(self.0, &mut data) })
588            .map(|_| PerformanceDecreaseReason::from_bits_truncate(data))
589    }
590
591    pub fn display_ids_all(&self) -> sys::Result<Vec<<display::NV_GPU_DISPLAYIDS as RawConversion>::Target>> {
592        trace!("gpu.display_ids_all()");
593        let mut count = 0;
594        sys::status_result(unsafe { display::NvAPI_GPU_GetAllDisplayIds(self.0, ptr::null_mut(), &mut count) })?;
595        if count == 0 {
596            return Ok(Vec::new());
597        }
598        let mut data = display::NV_GPU_DISPLAYIDS::zeroed();
599        data.version = display::NV_GPU_DISPLAYIDS_VER;
600        let mut data = vec![data; count as usize];
601
602        sys::status_result(unsafe { display::NvAPI_GPU_GetAllDisplayIds(self.0, data.as_mut_ptr(), &mut count) })
603            .and_then(|_| data.into_iter().map(|v| v.convert_raw().map_err(From::from)).collect())
604    }
605
606    pub fn display_ids_connected(&self, flags: ConnectedIdsFlags) -> sys::Result<Vec<<display::NV_GPU_DISPLAYIDS as RawConversion>::Target>> {
607        trace!("gpu.display_ids_connected({:?})", flags);
608        let mut count = 0;
609        sys::status_result(unsafe { display::NvAPI_GPU_GetConnectedDisplayIds(self.0, ptr::null_mut(), &mut count, flags.bits()) })?;
610        if count == 0 {
611            return Ok(Vec::new());
612        }
613        let mut data = display::NV_GPU_DISPLAYIDS::zeroed();
614        data.version = display::NV_GPU_DISPLAYIDS_VER;
615        let mut data = vec![data; count as usize];
616
617        sys::status_result(unsafe { display::NvAPI_GPU_GetConnectedDisplayIds(self.0, data.as_mut_ptr(), &mut count, flags.bits()) })
618            .and_then(|_| data.into_iter().map(|v| v.convert_raw().map_err(From::from)).collect())
619    }
620
621    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> {
622        trace!("i2c_read({}, {:?}, {:?}, 0x{:02x}, {:?}, {:?})", display_mask, port, port_is_ddc, address, register, speed);
623        let mut data = i2c::NV_I2C_INFO::zeroed();
624        data.version = i2c::NV_I2C_INFO_VER;
625        data.displayMask = display_mask;
626        data.bIsDDCPort = if port_is_ddc { sys::NV_TRUE } else { sys::NV_FALSE } as _;
627        data.i2cDevAddress = address << 1;
628        data.pbI2cRegAddress = if register.is_empty() { ptr::null_mut() } else { register.as_ptr() as *mut _ };
629        data.regAddrSize = register.len() as _;
630        data.pbData = bytes.as_mut_ptr();
631        data.cbSize = bytes.len() as _;
632        data.i2cSpeed = i2c::NVAPI_I2C_SPEED_DEPRECATED;
633        data.i2cSpeedKhz = speed.raw();
634        if let Some(port) = port {
635            data.portId = port;
636            data.bIsPortIdSet = sys::NV_TRUE as _;
637        }
638
639        sys::status_result(unsafe { i2c::NvAPI_I2CRead(self.0, &mut data) })
640            .map(|_| data.cbSize as usize) // TODO: not actually sure if this ever changes?
641    }
642
643    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<()> {
644        trace!("i2c_write({}, {:?}, {:?}, 0x{:02x}, {:?}, {:?})", display_mask, port, port_is_ddc, address, register, speed);
645        let mut data = i2c::NV_I2C_INFO::zeroed();
646        data.version = i2c::NV_I2C_INFO_VER;
647        data.displayMask = display_mask;
648        data.bIsDDCPort = if port_is_ddc { sys::NV_TRUE } else { sys::NV_FALSE } as _;
649        data.i2cDevAddress = address << 1;
650        data.pbI2cRegAddress = if register.is_empty() { ptr::null_mut() } else { register.as_ptr() as *mut _ };
651        data.regAddrSize = register.len() as _;
652        data.pbData = bytes.as_ptr() as *mut _;
653        data.cbSize = bytes.len() as _;
654        data.i2cSpeed = i2c::NVAPI_I2C_SPEED_DEPRECATED;
655        data.i2cSpeedKhz = speed.raw();
656        if let Some(port) = port {
657            data.portId = port;
658            data.bIsPortIdSet = sys::NV_TRUE as _;
659        }
660
661        sys::status_result(unsafe { i2c::NvAPI_I2CWrite(self.0, &mut data) })
662            .map(drop)
663    }
664}
665
666#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
667#[derive(Debug, Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)]
668pub struct PciIdentifiers {
669    pub device_id: u32,
670    pub subsystem_id: u32,
671    pub revision_id: u32,
672    pub ext_device_id: u32,
673}
674
675impl fmt::Display for PciIdentifiers {
676    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
677        write!(f, "{:08x} - {:08x} - {:08x} - {:x}", self.device_id, self.subsystem_id, self.ext_device_id, self.revision_id)
678    }
679}
680
681impl PciIdentifiers {
682    pub fn vendor_id(&self) -> u16 {
683        self.ids().0
684    }
685
686    pub fn product_id(&self) -> u16 {
687        self.ids().1
688    }
689
690    pub fn ids(&self) -> (u16, u16) {
691        let pid = (self.device_id >> 16) as u16;
692        let vid = self.device_id as u16;
693        if vid == 0x10de && self.subsystem_id != 0 {
694            let spid = (self.subsystem_id >> 16) as u16;
695            (
696                self.subsystem_id as u16,
697                if spid == 0 {
698                    // Colorful and Inno3D
699                    pid
700                } else {
701                    spid
702                }
703            )
704        } else {
705            (vid, pid)
706        }
707    }
708
709    pub fn vendor(&self) -> Result<Vendor, sys::ArgumentRangeError> {
710        Vendor::from_raw(self.vendor_id() as _)
711    }
712}
713
714#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
715#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
716pub struct MemoryInfo {
717    pub dedicated: Kibibytes,
718    pub dedicated_available: Kibibytes,
719    pub system: Kibibytes,
720    pub shared: Kibibytes,
721    pub dedicated_available_current: Kibibytes,
722    pub dedicated_evictions_size: Kibibytes,
723    pub dedicated_evictions: u32,
724}
725
726impl RawConversion for driverapi::NV_DISPLAY_DRIVER_MEMORY_INFO {
727    type Target = MemoryInfo;
728    type Error = Void;
729
730    fn convert_raw(&self) -> Result<Self::Target, Self::Error> {
731        Ok(MemoryInfo {
732            dedicated: Kibibytes(self.dedicatedVideoMemory),
733            dedicated_available: Kibibytes(self.availableDedicatedVideoMemory),
734            system: Kibibytes(self.systemVideoMemory),
735            shared: Kibibytes(self.sharedSystemMemory),
736            dedicated_available_current: Kibibytes(self.curAvailableDedicatedVideoMemory),
737            dedicated_evictions_size: Kibibytes(self.dedicatedVideoMemoryEvictionsSize),
738            dedicated_evictions: self.dedicatedVideoMemoryEvictionCount,
739        })
740    }
741}
742
743#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
744#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
745pub struct DriverModel {
746    pub value: u32,
747}
748
749impl DriverModel {
750    pub fn new(value: u32) -> Self {
751        DriverModel {
752            value: value,
753        }
754    }
755
756    pub fn wddm(&self) -> (u8, u8) {
757        // 2.0 or 1.(value >> 8)
758        let major = ((self.value >> 12) & 0xf) as u8;
759        (
760            major,
761            if major == 2 { 0 } else { (self.value >> 8) as u8 & 0xf }
762        )
763    }
764}
765
766impl fmt::Display for DriverModel {
767    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
768        let wddm = self.wddm();
769        write!(f, "WDDM {}.{:02}", wddm.0, wddm.1)
770    }
771}
772
773impl fmt::Debug for DriverModel {
774    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
775        write!(f, "{} ({:08x})", self, self.value)
776    }
777}
778
779#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
780#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
781pub struct DisplayId {
782    pub connector: MonitorConnectorType,
783    pub display_id: u32,
784    pub flags: DisplayIdsFlags,
785}
786
787impl RawConversion for display::NV_GPU_DISPLAYIDS {
788    type Target = DisplayId;
789    type Error = sys::ArgumentRangeError;
790
791    fn convert_raw(&self) -> Result<Self::Target, Self::Error> {
792        Ok(DisplayId {
793            connector: MonitorConnectorType::from_raw(self.connectorType)?,
794            display_id: self.displayId,
795            flags: DisplayIdsFlags::from_bits_truncate(self.flags),
796        })
797    }
798}