Skip to content

Commit 40bca5b

Browse files
committed
新增识别显卡节能状态,同时不再自动开关GPU监控。
1 parent 801c568 commit 40bca5b

3 files changed

Lines changed: 115 additions & 71 deletions

File tree

LibreHardwareMonitor/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Diagnostics;
33
using System.Globalization;
4-
using LibreHardwareMonitor.Hardware.Motherboard;
54
using LibreHardwareMonitor.Interop;
65

76
namespace LibreHardwareMonitor.Hardware.Gpu;
@@ -23,37 +22,65 @@ public NvidiaGpu(int adapterIndex, NvApi.NvPhysicalGpuHandle handle, NvApi.NvDis
2322
ActivateSensor(_temperature);
2423

2524
// 功率传感器 (NVML)
26-
if (NvidiaML.Initialize())
25+
if (NvidiaML.IsAvailable || NvidiaML.Initialize())
2726
{
28-
NvApi.NvAPI_GPU_GetBusId(handle, out uint busId);
29-
_nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0")
30-
?? NvidiaML.NvmlDeviceGetHandleByIndex(adapterIndex);
27+
if (NvApi.NvAPI_GPU_GetBusId(handle, out uint busId) == NvApi.NvStatus.OK)
28+
_nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0") ?? NvidiaML.NvmlDeviceGetHandleByIndex(adapterIndex);
29+
else
30+
_nvmlDevice = NvidiaML.NvmlDeviceGetHandleByIndex(adapterIndex);
31+
3132
if (_nvmlDevice.HasValue)
32-
{
3333
_powerUsage = new Sensor("GPU Package", 0, SensorType.Power, this, settings);
34-
// 注意:功率传感器在 Update 中激活,这里不激活避免无值
35-
}
3634
}
35+
36+
Update();
3737
}
3838

3939
public override string DeviceId => null;
4040

4141
public override HardwareType HardwareType => HardwareType.GpuNvidia;
4242

43+
/// <summary>
44+
/// 通过读取 GPU 性能状态判断是否休眠。
45+
/// GPU 活跃时返回 OK,休眠时返回非 OK(如原始错误码 -216 对应 NVAPI_GPU_NOT_POWERED),
46+
/// 且此调用本身不会唤醒 GPU。
47+
/// </summary>
48+
private bool IsGpuPowered()
49+
{
50+
if (NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx == null)
51+
return true; // API 不可用时保守处理,允许读取
52+
53+
var pStatesInfo = new NvApi.NvDynamicPStatesInfo
54+
{
55+
Version = (uint)NvApi.MAKE_NVAPI_VERSION<NvApi.NvDynamicPStatesInfo>(1),
56+
Utilizations = new NvApi.NvDynamicPState[NvApi.MAX_GPU_UTILIZATIONS]
57+
};
58+
59+
return NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx(_handle, ref pStatesInfo) == NvApi.NvStatus.OK;
60+
}
61+
4362
public override void Update()
4463
{
4564
try
4665
{
66+
if (!IsGpuPowered())
67+
{
68+
_temperature.Value = null;
69+
if (_powerUsage != null)
70+
_powerUsage.Value = null;
71+
return;
72+
}
73+
4774
// 温度
48-
var settings = new NvApi.NvThermalSettings
75+
var thermalSettings = new NvApi.NvThermalSettings
4976
{
5077
Version = (uint)NvApi.MAKE_NVAPI_VERSION<NvApi.NvThermalSettings>(2),
5178
Count = NvApi.MAX_THERMAL_SENSORS_PER_GPU
5279
};
53-
if (NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.All, ref settings) == NvApi.NvStatus.OK
54-
&& settings.Count > 0)
80+
if (NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.All, ref thermalSettings) == NvApi.NvStatus.OK
81+
&& thermalSettings.Count > 0)
5582
{
56-
_temperature.Value = settings.Sensor[0].CurrentTemp;
83+
_temperature.Value = thermalSettings.Sensor[0].CurrentTemp;
5784
}
5885

5986
// 功率

Program.cs

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,14 @@ static void RunHardwareMonitor() {
591591
if (sensor.SensorType == LibreSensorType.Temperature && sensor.Name == "GPU Core")
592592
tGpu = sensor.Value.GetValueOrDefault();
593593
if (sensor.SensorType == LibreSensorType.Power && sensor.Name == "GPU Package") {
594-
gGpu = true;
595-
pGpu = sensor.Value.GetValueOrDefault();
594+
if (sensor.Value.HasValue) {
595+
pGpu = sensor.Value.GetValueOrDefault();
596+
gGpu = true;
597+
}
598+
else {
599+
pGpu = -1;
600+
gGpu = false;
601+
}
596602
}
597603
}
598604
} catch { }
@@ -639,10 +645,16 @@ static void StartHardwareMonitor() {
639645
smoothedCPUTemp = rawTempCPU;
640646
cpuTempReady = true;
641647
}
642-
if (!gpuTempReady) {
648+
if (!gpuTempReady && rawGotGPU) {
643649
smoothedGPUTemp = rawTempGPU;
644650
gpuTempReady = true;
645651
}
652+
if (!rawGotGPU) {
653+
gpuTempReady = false;
654+
GPUTemp = 40;
655+
GPUPower = 0;
656+
}
657+
646658
if (!tempReady) {
647659
tempReady = true;
648660
// 首次获取到数据立即刷新
@@ -1182,60 +1194,60 @@ static void QueryHardware() {
11821194
//通过countQuery延时来确保温度正常读取
11831195
if (countQuery <= 5 && monitorGPU)
11841196
countQuery++;
1185-
//自动关闭GPU监控
1186-
if (countQuery > 5 && autoStopMonitorGPU && !isConnectedToNVIDIA && monitorGPU && ((GPUPower >= 0 && GPUPower <= 1.3) || !getGPU)) {
1187-
// 如果是NVIDIAGpu平台,进一步检查是否有程序占用GPU
1188-
bool isGpuIdle = true;
1189-
if (hasNVIDIAGpu) {
1190-
var gpuApps = GetGpuApps();
1191-
if (gpuApps != null && gpuApps.Count > 0) {
1192-
isGpuIdle = false;
1193-
}
1194-
}
1195-
1196-
if (isGpuIdle) {
1197-
GPUPower = 0;
1198-
rawPowerGPU = 0f;
1199-
getGPU = false;
1200-
hasStopAuto = true;
1201-
countQuery = 0;
1202-
monitorGPU = false;
1203-
gpuTempReady = false; // 关闭后温度不再有效
1204-
//重置自动开启标志
1205-
hasStartAuto = false;
1206-
autoStartMonitorGPU = true;
1207-
SetGpuMonitorState(false);
1208-
UpdateCheckedState("monitorGPUGroup", Strings.MonitorGpuOff);
1209-
SaveConfig("MonitorGPU");
1210-
1211-
// 设置通知的文本和标题
1212-
trayIcon.BalloonTipTitle = Strings.GpuAutoStopTitle;
1213-
trayIcon.BalloonTipText = Strings.GpuAutoStopText;
1214-
trayIcon.BalloonTipIcon = ToolTipIcon.Info; // 图标类型
1215-
trayIcon.ShowBalloonTip(3000); // 显示气泡通知,持续时间为 3 秒
1216-
}
1217-
}
1218-
//自动开启GPU监控:需为自动转速控制且从"未连接显示器"切换为"已连接"时才触发
1219-
if (autoStartMonitorGPU && isConnectedToNVIDIA && !prevIsConnectedToNVIDIA && !monitorGPU && fanControl == "auto") {
1220-
GPUPower = 0;
1221-
rawPowerGPU = 0f;
1222-
hasStartAuto = true;
1223-
countQuery = 0;
1224-
monitorGPU = true;
1225-
gpuTempReady = false; // 等待获取到温度后再参与风扇控制
1226-
//重置自动关闭标志
1227-
hasStopAuto = false;
1228-
autoStopMonitorGPU = true;
1229-
SetGpuMonitorState(true);
1230-
UpdateCheckedState("monitorGPUGroup", Strings.MonitorGpuOn);
1231-
SaveConfig("MonitorGPU");
1232-
1233-
// 设置通知的文本和标题
1234-
trayIcon.BalloonTipTitle = Strings.GpuAutoStopTitle;
1235-
trayIcon.BalloonTipText = Strings.GpuAutoStartText;
1236-
trayIcon.BalloonTipIcon = ToolTipIcon.Info; // 图标类型
1237-
trayIcon.ShowBalloonTip(3000); // 显示气泡通知,持续时间为 3 秒
1238-
}
1197+
////自动关闭GPU监控
1198+
//if (countQuery > 5 && autoStopMonitorGPU && !isConnectedToNVIDIA && monitorGPU && ((GPUPower >= 0 && GPUPower <= 1.3) || !getGPU)) {
1199+
// // 如果是NVIDIAGpu平台,进一步检查是否有程序占用GPU
1200+
// bool isGpuIdle = true;
1201+
// if (hasNVIDIAGpu) {
1202+
// var gpuApps = GetGpuApps();
1203+
// if (gpuApps != null && gpuApps.Count > 0) {
1204+
// isGpuIdle = false;
1205+
// }
1206+
// }
1207+
1208+
// if (isGpuIdle) {
1209+
// GPUPower = 0;
1210+
// rawPowerGPU = 0f;
1211+
// getGPU = false;
1212+
// hasStopAuto = true;
1213+
// countQuery = 0;
1214+
// monitorGPU = false;
1215+
// gpuTempReady = false; // 关闭后温度不再有效
1216+
// //重置自动开启标志
1217+
// hasStartAuto = false;
1218+
// autoStartMonitorGPU = true;
1219+
// SetGpuMonitorState(false);
1220+
// UpdateCheckedState("monitorGPUGroup", Strings.MonitorGpuOff);
1221+
// SaveConfig("MonitorGPU");
1222+
1223+
// // 设置通知的文本和标题
1224+
// trayIcon.BalloonTipTitle = Strings.GpuAutoStopTitle;
1225+
// trayIcon.BalloonTipText = Strings.GpuAutoStopText;
1226+
// trayIcon.BalloonTipIcon = ToolTipIcon.Info; // 图标类型
1227+
// trayIcon.ShowBalloonTip(3000); // 显示气泡通知,持续时间为 3 秒
1228+
// }
1229+
//}
1230+
////自动开启GPU监控:需为自动转速控制且从"未连接显示器"切换为"已连接"时才触发
1231+
//if (autoStartMonitorGPU && isConnectedToNVIDIA && !prevIsConnectedToNVIDIA && !monitorGPU && fanControl == "auto") {
1232+
// GPUPower = 0;
1233+
// rawPowerGPU = 0f;
1234+
// hasStartAuto = true;
1235+
// countQuery = 0;
1236+
// monitorGPU = true;
1237+
// gpuTempReady = false; // 等待获取到温度后再参与风扇控制
1238+
// //重置自动关闭标志
1239+
// hasStopAuto = false;
1240+
// autoStopMonitorGPU = true;
1241+
// SetGpuMonitorState(true);
1242+
// UpdateCheckedState("monitorGPUGroup", Strings.MonitorGpuOn);
1243+
// SaveConfig("MonitorGPU");
1244+
1245+
// // 设置通知的文本和标题
1246+
// trayIcon.BalloonTipTitle = Strings.GpuAutoStopTitle;
1247+
// trayIcon.BalloonTipText = Strings.GpuAutoStartText;
1248+
// trayIcon.BalloonTipIcon = ToolTipIcon.Info; // 图标类型
1249+
// trayIcon.ShowBalloonTip(3000); // 显示气泡通知,持续时间为 3 秒
1250+
//}
12391251

12401252
// 似乎无法一次性关闭GPU监控及选项
12411253
//if (!monitorGPU) {
@@ -1333,8 +1345,12 @@ static string monitorText() {
13331345
}
13341346
if (monitorGPU) {
13351347
if (str.Length > 0) str += "\n";
1336-
if (pawnIOState == "RUNNING" && !gpuTempReady)
1337-
str += $"GPU: {Strings.MonitorPrepareLabel}";
1348+
if (pawnIOState == "RUNNING" && !gpuTempReady) {
1349+
if (rawPowerGPU < 0)
1350+
str += $"GPU: {Strings.GpuPoweredOff}";
1351+
else
1352+
str += $"GPU: {Strings.MonitorPrepareLabel}";
1353+
}
13381354
else if (pawnIOState.Length > 0)
13391355
str += $"GPU: {GPUTemp:F1}°C, {GPUPower:F1}W";
13401356
}

Strings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,7 @@ public static string OmenKeyShortcutSendFailed(int error) => T(
593593
public static string MonitorCpuLabel => T("CPU", "CPU", "CPU");
594594
public static string MonitorGpuLabel => T("GPU", "GPU", "GPU");
595595
public static string MonitorFanLabel => T("风扇", "風扇", "Fan");
596+
public static string GpuPoweredOff => T("节能", "節能", "PoweredOff");
596597
public static string MonitorPrepareLabel => T("数据获取中...", "數據獲取中...", "Retrieving data...");
597598

598599
// ─────────────────────────────────────────────────────────────────────────

0 commit comments

Comments
 (0)