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 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 }
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 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 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) }
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 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 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}