diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index 853f758..f3e6197 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -42,6 +42,7 @@ internal sealed class NvidiaGpu : GenericGpu private readonly Sensor _pcieThroughputTx; private readonly Sensor[] _powers; private readonly Sensor _powerUsage; + private readonly Sensor _coreVoltage; private readonly Sensor[] _temperatures; private readonly uint _thermalSensorsMask; @@ -307,6 +308,15 @@ internal sealed class NvidiaGpu : GenericGpu } } + // Voltage + var voltageSensor = GetVoltRailsStatus(out status); + if (status == NvApi.NvStatus.OK) + { + _coreVoltage = new Sensor("GPU Core Voltage", 0, SensorType.Voltage, this, settings); + + ActivateSensor(_coreVoltage); + } + if (NvidiaML.IsAvailable || NvidiaML.Initialize()) { if (hasBusId) @@ -614,6 +624,17 @@ internal sealed class NvidiaGpu : GenericGpu } } + if (_coreVoltage != null) + { + var voltageSensor = GetVoltRailsStatus(out status); + if (status == NvApi.NvStatus.OK) + { + var microvolts = ((ulong)voltageSensor.CoreMicrovoltsHigh << 32) | voltageSensor.CoreMicrovolts; + + _coreVoltage.Value = microvolts == 0 ? 0 : microvolts / 1_000_000f; + } + } + if (_displayHandle != null) { NvApi.NvMemoryInfo memoryInfo = GetMemoryInfo(out status); @@ -1038,6 +1059,23 @@ internal sealed class NvidiaGpu : GenericGpu return status == NvApi.NvStatus.OK ? thermalSensors : default; } + private NvApi.NvGpuClientVoltRailsStatus GetVoltRailsStatus(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ClientVoltRailsGetStatus == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + var voltRails = new NvApi.NvGpuClientVoltRailsStatus + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + }; + + status = NvApi.NvAPI_GPU_ClientVoltRailsGetStatus(_handle, ref voltRails); + return status == NvApi.NvStatus.OK ? voltRails : default; + } + private NvApi.NvFanCoolersStatus GetFanCoolersStatus(out NvApi.NvStatus status) { if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus == null) diff --git a/LibreHardwareMonitorLib/Interop/NvApi.cs b/LibreHardwareMonitorLib/Interop/NvApi.cs index 0aa80b2..2513942 100644 --- a/LibreHardwareMonitorLib/Interop/NvApi.cs +++ b/LibreHardwareMonitorLib/Interop/NvApi.cs @@ -46,6 +46,7 @@ internal static class NvApi public static NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages { get; internal set; } public static NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels { get; internal set; } public static NvAPI_GPU_GetThermalSensorsDelegate NvAPI_GPU_GetThermalSensors { get; internal set; } + public static NvAPI_GPU_ClientVoltRailsGetStatusDelegate NvAPI_GPU_ClientVoltRailsGetStatus { get; internal set; } private static NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; private static NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; @@ -90,6 +91,7 @@ internal static class NvApi NvAPI_GPU_ClientFanCoolersSetControl = GetDelegate(0xA58971A5); NvAPI_GPU_ClientPowerTopologyGetStatus = GetDelegate(0x0EDCF624E); NvAPI_GPU_GetThermalSensors = GetDelegate(0x65FE3AAD); + NvAPI_GPU_ClientVoltRailsGetStatus = GetDelegate(0x465F9BCF); IsAvailable = true; } @@ -158,6 +160,9 @@ internal static class NvApi [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvCoolerLevels NvCoolerLevels); + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientVoltRailsGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvGpuClientVoltRailsStatus status); + public enum NvFanControlMode : uint { Auto = 0, @@ -577,6 +582,17 @@ internal static class NvApi public NvGpuClockFrequenciesDomain[] Clocks; } + [StructLayout(LayoutKind.Explicit, Size = 0x4C)] + internal unsafe struct NvGpuClientVoltRailsStatus + { + [FieldOffset(0x00)] public uint Version; + + [FieldOffset(0x04)] public fixed uint _reserved[17]; //Unknown + + [FieldOffset(0x28)] public uint CoreMicrovolts; + [FieldOffset(0x2C)] public uint CoreMicrovoltsHigh; + } + internal enum NvGpuPublicClockId { Graphics = 0,