diff --git a/LibreHardwareMonitorLib/Hardware/Control.cs b/LibreHardwareMonitorLib/Hardware/Control.cs index efd9be7..03f876a 100644 --- a/LibreHardwareMonitorLib/Hardware/Control.cs +++ b/LibreHardwareMonitorLib/Hardware/Control.cs @@ -23,8 +23,10 @@ namespace LibreHardwareMonitor.Hardware float minSoftwareValue, float maxSoftwareValue) { - Identifier = new Identifier(sensor.Identifier, "control"); _settings = settings; + + Identifier = new Identifier(sensor.Identifier, "control"); + Sensor = sensor; MinSoftwareValue = minSoftwareValue; MaxSoftwareValue = maxSoftwareValue; @@ -42,6 +44,10 @@ namespace LibreHardwareMonitor.Hardware _mode = (ControlMode)mode; } + internal event ControlEventHandler ControlModeChanged; + + internal event ControlEventHandler SoftwareControlValueChanged; + public ControlMode ControlMode { get { return _mode; } @@ -62,6 +68,8 @@ namespace LibreHardwareMonitor.Hardware public float MinSoftwareValue { get; } + public ISensor Sensor { get; } + public float SoftwareValue { get { return _softwareValue; } @@ -86,9 +94,5 @@ namespace LibreHardwareMonitor.Hardware ControlMode = ControlMode.Software; SoftwareValue = value; } - - internal event ControlEventHandler ControlModeChanged; - - internal event ControlEventHandler SoftwareControlValueChanged; } } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index c464bcb..03a893c 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -5,10 +5,16 @@ // All Rights Reserved. using System; +using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text; using LibreHardwareMonitor.Interop; using Microsoft.Win32; +using NvAPIWrapper.GPU; +using NvAPIWrapper.Native.Exceptions; +using NvAPIWrapper.Native.GPU; +using NvAPIWrapper.Native.GPU.Structures; namespace LibreHardwareMonitor.Hardware.Gpu { @@ -16,109 +22,184 @@ namespace LibreHardwareMonitor.Hardware.Gpu { private readonly int _adapterIndex; private readonly Sensor[] _clocks; - private readonly Sensor _control; - private readonly NvApi.NvDisplayHandle? _displayHandle; - private readonly Sensor _fan; - private readonly Control _fanControl; + private readonly Sensor[] _controls; + private readonly Control[] _fanControls; + private readonly Sensor[] _fans; private readonly Sensor _gpuDedicatedMemoryUsage; private readonly Sensor[] _gpuNodeUsage; private readonly DateTime[] _gpuNodeUsagePrevTick; private readonly long[] _gpuNodeUsagePrevValue; private readonly Sensor _gpuSharedMemoryUsage; - private readonly NvApi.NvPhysicalGpuHandle _handle; private readonly Sensor[] _loads; - private readonly Sensor _memoryAvail; private readonly Sensor _memoryFree; - private readonly Sensor _memoryLoad; - private readonly int _memorySensorIndex; + private readonly Sensor _memoryTotal; private readonly Sensor _memoryUsed; - private readonly int _nodeSensorIndex; private readonly NvidiaML.NvmlDevice? _nvmlDevice; private readonly Sensor _pcieThroughputRx; private readonly Sensor _pcieThroughputTx; + private readonly PhysicalGPU _physicalGpu; + private readonly Sensor[] _powers; private readonly Sensor _powerUsage; private readonly Sensor[] _temperatures; private readonly string _windowsDeviceName; - public NvidiaGpu(int adapterIndex, NvApi.NvPhysicalGpuHandle handle, NvApi.NvDisplayHandle? displayHandle, ISettings settings) - : base(GetName(handle), new Identifier("gpu-nvidia", adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) + public NvidiaGpu(int adapterIndex, PhysicalGPU physicalGpu, ISettings settings) + : base(GetName(physicalGpu), + new Identifier("gpu-nvidia", adapterIndex.ToString(CultureInfo.InvariantCulture)), + settings) { _adapterIndex = adapterIndex; - _handle = handle; - _displayHandle = displayHandle; + _physicalGpu = physicalGpu; - bool hasPciBusId = NvApi.NvAPI_GPU_GetBusId(handle, out uint busId) == NvApi.NvStatus.OK; + int busId = -1; - NvApi.NvGPUThermalSettings thermalSettings = GetThermalSettings(); - _temperatures = new Sensor[thermalSettings.Count]; - for (int i = 0; i < _temperatures.Length; i++) + try { - NvApi.NvSensor sensor = thermalSettings.Sensor[i]; - string name; - switch (sensor.Target) + busId = physicalGpu.BusInformation.BusId; + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + GPUThermalSensor[] thermalSensors = physicalGpu.ThermalInformation.ThermalSensors.ToArray(); + _temperatures = new Sensor[thermalSensors.Length]; + + for (int i = 0; i < thermalSensors.Length; i++) { - case NvApi.NvThermalTarget.BOARD: - name = "GPU Board"; - break; - case NvApi.NvThermalTarget.GPU: - name = "GPU Core"; - break; - case NvApi.NvThermalTarget.MEMORY: - name = "GPU Memory"; - break; - case NvApi.NvThermalTarget.POWER_SUPPLY: - name = "GPU Power Supply"; - break; - case NvApi.NvThermalTarget.UNKNOWN: - name = "GPU Unknown"; - break; - default: - name = "GPU"; - break; + GPUThermalSensor sensor = thermalSensors[i]; + + string name = sensor.Target switch + { + ThermalSettingsTarget.GPU => "GPU Core", + ThermalSettingsTarget.Memory => "GPU Memory", + ThermalSettingsTarget.PowerSupply => "GPU Power Supply", + ThermalSettingsTarget.Board => "GPU Board", + ThermalSettingsTarget.VisualComputingBoard => "GPU Visual Computing Board", + ThermalSettingsTarget.VisualComputingInlet => "GPU Visual Computing Inlet", + ThermalSettingsTarget.VisualComputingOutlet => "GPU Visual Computing Outlet", + _ => "GPU" + }; + + _temperatures[i] = new Sensor(name, i, SensorType.Temperature, this, new ParameterDescription[0], settings); + ActivateSensor(_temperatures[i]); + } + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + KeyValuePair[] clocks = physicalGpu.CurrentClockFrequencies.Clocks.OrderBy(x => x.Key).ToArray(); + _clocks = new Sensor[clocks.Length]; + + for (int i = 0; i < clocks.Length; i++) + { + KeyValuePair clock = clocks[i]; + + string name = clock.Key switch + { + PublicClockDomain.Graphics => "GPU Core", + PublicClockDomain.Memory => "GPU Memory", + PublicClockDomain.Processor => "GPU Shader", + PublicClockDomain.Video => "GPU Video", + _ => null + }; + + _clocks[i] = new Sensor(name, i, SensorType.Clock, this, settings); + ActivateSensor(_clocks[i]); + } + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + GPUUsageDomainStatus[] usages = physicalGpu.UsageInformation.UtilizationDomainsStatus.ToArray(); + _loads = new Sensor[usages.Length + 1]; + + for (int i = 0; i < usages.Length; i++) + { + string name = usages[i].Domain switch + { + UtilizationDomain.GPU => "GPU Core", + UtilizationDomain.FrameBuffer => "GPU Memory Controller", + UtilizationDomain.VideoEngine => "GPU Video Engine", + UtilizationDomain.BusInterface => "GPU Bus", + _ => null + }; + + _loads[i] = new Sensor(name, i, SensorType.Load, this, settings); + ActivateSensor(_loads[i]); } - _temperatures[i] = new Sensor(name, i, SensorType.Temperature, this, new ParameterDescription[0], settings); - ActivateSensor(_temperatures[i]); + _loads[_loads.Length - 1] = new Sensor("GPU Memory", _loads.Length - 1, SensorType.Load, this, settings); + ActivateSensor(_loads[_loads.Length - 1]); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - if (NvApi.NvAPI_GPU_GetTachReading != null && NvApi.NvAPI_GPU_GetTachReading(handle, out _) == NvApi.NvStatus.OK) - _fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); - else if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null && GetCoolerSettings().Count > 0) - _fan = new Sensor("GPU", 0, SensorType.Fan, this, settings); - - _clocks = new Sensor[3]; - _clocks[0] = new Sensor("GPU Core", 0, SensorType.Clock, this, settings); - _clocks[1] = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings); - _clocks[2] = new Sensor("GPU Shader", 2, SensorType.Clock, this, settings); - for (int i = 0; i < _clocks.Length; i++) - ActivateSensor(_clocks[i]); - - _loads = new Sensor[4]; - _loads[0] = new Sensor("GPU Core", 0, SensorType.Load, this, settings); - _loads[1] = new Sensor("GPU Memory Controller", 1, SensorType.Load, this, settings); - _loads[2] = new Sensor("GPU Video Engine", 2, SensorType.Load, this, settings); - _loads[3] = new Sensor("GPU Bus", 4, SensorType.Load, this, settings); - - _memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings); - _memoryFree = new Sensor("GPU Memory Free", 1, SensorType.SmallData, this, settings); - _memoryUsed = new Sensor("GPU Memory Used", 2, SensorType.SmallData, this, settings); - _memoryAvail = new Sensor("GPU Memory Total", 3, SensorType.SmallData, this, settings); - - _control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); - - NvApi.NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); - if (coolerSettings.Count > 0) + try { - _fanControl = new Control(_control, settings, coolerSettings.Cooler[0].DefaultMin, coolerSettings.Cooler[0].DefaultMax); - _fanControl.ControlModeChanged += ControlModeChanged; - _fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged; - ControlModeChanged(_fanControl); - _control.Control = _fanControl; + GPUCooler[] coolers = physicalGpu.CoolerInformation.Coolers.ToArray(); + if (coolers.Length > 0) + { + _controls = new Sensor[coolers.Length]; + _fanControls = new Control[coolers.Length]; + _fans = new Sensor[coolers.Length]; + + for (int i = 0; i < coolers.Length; i++) + { + GPUCooler cooler = coolers[i]; + string name = "GPU Fan" + (coolers.Length > 1 ? " " + (cooler.CoolerId) : string.Empty); + + _fans[i] = new Sensor(name, i, SensorType.Fan, this, settings); + ActivateSensor(_fans[i]); + + _controls[i] = new Sensor(name, i, SensorType.Control, this, settings); + ActivateSensor(_controls[i]); + + _fanControls[i] = new Control(_controls[i], settings, cooler.DefaultMinimumLevel, cooler.DefaultMaximumLevel); + _fanControls[i].ControlModeChanged += ControlModeChanged; + _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; + _controls[i].Control = _fanControls[i]; + + ControlModeChanged(_fanControls[i]); + } + } } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + GPUPowerTopologyStatus[] powerTopologies = physicalGpu.PowerTopologyInformation.PowerTopologyEntries.ToArray(); + if (powerTopologies.Length > 0) + { + _powers = new Sensor[powerTopologies.Length]; + + for (int i = 0; i < powerTopologies.Length; i++) + { + GPUPowerTopologyStatus powerTopology = powerTopologies[i]; + + string name = powerTopology.Domain switch + { + PowerTopologyDomain.GPU => "GPU Power", + PowerTopologyDomain.Board => "GPU Board Power", + _ => null + }; + + _powers[i] = new Sensor(name, i + (_loads?.Length ?? 0), SensorType.Load, this, settings); + ActivateSensor(_powers[i]); + } + } + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } if (NvidiaML.IsAvailable || NvidiaML.Initialize()) { - if (hasPciBusId) + if (busId != -1) _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0") ?? NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); else _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); @@ -203,10 +284,13 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (isMatch && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceIdentifier, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) { + int nodeSensorIndex = (_loads?.Length ?? 0) + (_powers?.Length ?? 0); + int memorySensorIndex = 3; // There are three normal GPU memory sensors. + _windowsDeviceName = deviceIdentifier; - _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", _memorySensorIndex++, SensorType.SmallData, this, settings); - _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", _memorySensorIndex++, SensorType.SmallData, this, settings); + _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex, SensorType.SmallData, this, settings); _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; @@ -214,7 +298,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) { - _gpuNodeUsage[node.Id] = new Sensor(node.Name, _nodeSensorIndex++, SensorType.Load, this, settings); + _gpuNodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; } @@ -227,6 +311,10 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } + _memoryFree = new Sensor("GPU Memory Free", 0, SensorType.SmallData, this, settings); + _memoryUsed = new Sensor("GPU Memory Used", 1, SensorType.SmallData, this, settings); + _memoryTotal = new Sensor("GPU Memory Total", 2, SensorType.SmallData, this, settings); + Update(); } @@ -235,67 +323,24 @@ namespace LibreHardwareMonitor.Hardware.Gpu get { return HardwareType.GpuNvidia; } } - private static string GetName(NvApi.NvPhysicalGpuHandle handle) + private static string GetName(PhysicalGPU physicalGpu) { - if (NvApi.NvAPI_GPU_GetFullName(handle, out string gpuName) == NvApi.NvStatus.OK) - { - gpuName = gpuName.Trim(); - if (gpuName.StartsWith("NVIDIA", StringComparison.OrdinalIgnoreCase)) - return gpuName; + string gpuName = null; - return "NVIDIA " + gpuName.Trim(); + try + { + gpuName = physicalGpu.FullName?.Trim(); } + catch (NVIDIAApiException) + { } - return "NVIDIA"; - } + gpuName ??= "Unknown"; - private NvApi.NvGPUThermalSettings GetThermalSettings() - { - NvApi.NvGPUThermalSettings settings = new() - { - Version = NvApi.GPU_THERMAL_SETTINGS_VER, Count = NvApi.MAX_THERMAL_SENSORS_PER_GPU, Sensor = new NvApi.NvSensor[NvApi.MAX_THERMAL_SENSORS_PER_GPU] - }; + if (gpuName.StartsWith("NVIDIA", StringComparison.OrdinalIgnoreCase)) + return gpuName; - if (!(NvApi.NvAPI_GPU_GetThermalSettings != null && NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.ALL, ref settings) == NvApi.NvStatus.OK)) - { - settings.Count = 0; - } - return settings; - } - - private NvApi.NvFanCoolersStatus GetFanCoolersStatus() - { - var coolers = new NvApi.NvFanCoolersStatus { Version = NvApi.GPU_FAN_COOLERS_STATUS_VER, Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] }; - - if (!(NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null && NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers) == NvApi.NvStatus.OK)) - { - coolers.Count = 0; - } - - return coolers; - } - - private NvApi.NvGPUCoolerSettings GetCoolerSettings() - { - NvApi.NvGPUCoolerSettings settings = new() { Version = NvApi.GPU_COOLER_SETTINGS_VER, Cooler = new NvApi.NvCooler[NvApi.MAX_COOLER_PER_GPU] }; - if (!(NvApi.NvAPI_GPU_GetCoolerSettings != null && NvApi.NvAPI_GPU_GetCoolerSettings(_handle, 0, ref settings) == NvApi.NvStatus.OK)) - { - settings.Count = 0; - } - - return settings; - } - - private uint[] GetClocks() - { - NvApi.NvClocks allClocks = new() { Version = NvApi.GPU_CLOCKS_VER, Clock = new uint[NvApi.MAX_CLOCKS_PER_GPU] }; - if (NvApi.NvAPI_GPU_GetAllClocks != null && NvApi.NvAPI_GPU_GetAllClocks(_handle, ref allClocks) == NvApi.NvStatus.OK) - { - return allClocks.Clock; - } - - return null; + return "NVIDIA " + gpuName.Trim(); } public override void Update() @@ -319,111 +364,100 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } - NvApi.NvGPUThermalSettings settings = GetThermalSettings(); - // settings.Count is 0 when no valid data available, this happens when you try to read out this value with a high polling interval. - if (settings.Count > 0) + try { - foreach (Sensor sensor in _temperatures) - sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; - } - - bool readTach = false; - if (_fan != null) - { - if (NvApi.NvAPI_GPU_GetTachReading(_handle, out int value) == NvApi.NvStatus.OK) + if (_temperatures is { Length: > 0 }) { - _fan.Value = value; - ActivateSensor(_fan); - - readTach = true; - } - } - - uint[] values = GetClocks(); - if (values != null) - { - _clocks[1].Value = 0.001f * values[8]; - if (values[30] != 0) - { - _clocks[0].Value = 0.0005f * values[30]; - _clocks[2].Value = 0.001f * values[30]; - } - else - { - _clocks[0].Value = 0.001f * values[0]; - _clocks[2].Value = 0.001f * values[14]; - } - } - - NvApi.NvPStates states = new() { Version = NvApi.GPU_PSTATES_VER, PStates = new NvApi.NvPState[NvApi.MAX_PSTATES_PER_GPU] }; - if (NvApi.NvAPI_GPU_GetPStates != null && NvApi.NvAPI_GPU_GetPStates(_handle, ref states) == NvApi.NvStatus.OK) - { - for (int i = 0; i < _loads.Length; i++) - { - if (states.PStates[i].Present) + GPUThermalSensor[] thermalSensors = _physicalGpu.ThermalInformation.ThermalSensors.ToArray(); + for (int i = 0; i < thermalSensors.Length; i++) { - _loads[i].Value = states.PStates[i].Percentage; - ActivateSensor(_loads[i]); + GPUThermalSensor sensor = thermalSensors[i]; + _temperatures[i].Value = sensor.CurrentTemperature; } } } - else + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try { - NvApi.NvUsages usages = new() { Version = NvApi.GPU_USAGES_VER, Usage = new uint[NvApi.MAX_USAGES_PER_GPU] }; - if (NvApi.NvAPI_GPU_GetUsages != null && NvApi.NvAPI_GPU_GetUsages(_handle, ref usages) == NvApi.NvStatus.OK) + if (_clocks is { Length: > 0 }) { - _loads[0].Value = usages.Usage[2]; - _loads[1].Value = usages.Usage[6]; - _loads[2].Value = usages.Usage[10]; - for (int i = 0; i < 3; i++) - ActivateSensor(_loads[i]); - } - } - - bool readCoolerSettings = false; - NvApi.NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); - if (coolerSettings.Count > 0) - { - _control.Value = coolerSettings.Cooler[0].CurrentLevel; - ActivateSensor(_control); - - readCoolerSettings = true; - } - - if (!readTach || !readCoolerSettings) - { - NvApi.NvFanCoolersStatus coolersStatus = GetFanCoolersStatus(); - if (coolersStatus.Count > 0) - { - if (!readCoolerSettings) + KeyValuePair[] clocks = _physicalGpu.CurrentClockFrequencies.Clocks.OrderBy(x => x.Key).ToArray(); + for (int i = 0; i < clocks.Length; i++) { - _control.Value = coolersStatus.Items[0].CurrentLevel; - ActivateSensor(_control); - } - - if (!readTach && _fan != null) - { - _fan.Value = coolersStatus.Items[0].CurrentRpm; - ActivateSensor(_fan); + KeyValuePair clock = clocks[i]; + _clocks[i].Value = clock.Value.Frequency / 1000f; } } } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - NvApi.NvMemoryInfo memoryInfo = new() { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; - if (NvApi.NvAPI_GPU_GetMemoryInfo != null && _displayHandle.HasValue && NvApi.NvAPI_GPU_GetMemoryInfo(_displayHandle.Value, ref memoryInfo) == NvApi.NvStatus.OK) + GPUMemoryInformation memoryInformation = _physicalGpu.MemoryInformation; + + try { - uint totalMemory = memoryInfo.Values[0]; - uint freeMemory = memoryInfo.Values[4]; - float usedMemory = Math.Max(totalMemory - freeMemory, 0); - _memoryFree.Value = (float)freeMemory / 1024; - _memoryAvail.Value = (float)totalMemory / 1024; - _memoryUsed.Value = usedMemory / 1024; - _memoryLoad.Value = 100f * usedMemory / totalMemory; - ActivateSensor(_memoryAvail); + GPUUsageDomainStatus[] usages = _physicalGpu.UsageInformation.UtilizationDomainsStatus.ToArray(); + for (int i = 0; i < usages.Length; i++) + _loads[i].Value = usages[i].Percentage; + + uint current = memoryInformation.CurrentAvailableDedicatedVideoMemoryInkB; + uint total = memoryInformation.DedicatedVideoMemoryInkB; + + _loads[_loads.Length - 1].Value = 100f * (total - current) / total; + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + GPUCooler[] coolers = _physicalGpu.CoolerInformation.Coolers.ToArray(); + if (coolers.Length > 0) + { + for (int i = 0; i < coolers.Length; i++) + { + GPUCooler cooler = coolers[i]; + + _fans[i].Value = cooler.CurrentFanSpeedInRPM; + _controls[i].Value = cooler.CurrentLevel; + } + } + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + GPUPowerTopologyStatus[] powerTopologies = _physicalGpu.PowerTopologyInformation.PowerTopologyEntries.ToArray(); + if (powerTopologies.Length > 0) + { + for (int i = 0; i < powerTopologies.Length; i++) + { + GPUPowerTopologyStatus powerTopology = powerTopologies[i]; + _powers[i].Value = powerTopology.PowerUsageInPercent; + } + } + } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } + + try + { + uint current = memoryInformation.CurrentAvailableDedicatedVideoMemoryInkB; + uint total = memoryInformation.DedicatedVideoMemoryInkB; + + _memoryTotal.Value = total / 1024; + ActivateSensor(_memoryTotal); + + _memoryUsed.Value = current / 1024; ActivateSensor(_memoryUsed); + + _memoryFree.Value = (total - current) / 1024; ActivateSensor(_memoryFree); - ActivateSensor(_memoryLoad); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } if (NvidiaML.IsAvailable && _nvmlDevice.HasValue) { @@ -460,271 +494,139 @@ namespace LibreHardwareMonitor.Hardware.Gpu r.AppendFormat("Name: {0}{1}", _name, Environment.NewLine); r.AppendFormat("Index: {0}{1}", _adapterIndex, Environment.NewLine); - if (_displayHandle.HasValue && NvApi.NvAPI_GetDisplayDriverVersion != null) + try { - NvApi.NvDisplayDriverVersion driverVersion = new() { Version = NvApi.DISPLAY_DRIVER_VERSION_VER }; - if (NvApi.NvAPI_GetDisplayDriverVersion(_displayHandle.Value, ref driverVersion) == NvApi.NvStatus.OK) - { - r.Append("Driver Version: "); - r.Append(driverVersion.DriverVersion / 100); - r.Append("."); - r.Append((driverVersion.DriverVersion % 100).ToString("00", CultureInfo.InvariantCulture)); - r.AppendLine(); - r.Append("Driver Branch: "); - r.AppendLine(driverVersion.BuildBranch); - } + PCIIdentifiers pciIdentifiers = _physicalGpu.BusInformation.PCIIdentifiers; + r.Append("DeviceID: 0x"); + r.AppendLine(pciIdentifiers.DeviceId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("SubSystemID: 0x"); + r.AppendLine(pciIdentifiers.SubSystemId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("RevisionID: 0x"); + r.AppendLine(pciIdentifiers.RevisionId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("ExtDeviceID: 0x"); + r.AppendLine(pciIdentifiers.ExternalDeviceId.ToString("X", CultureInfo.InvariantCulture)); + r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - r.AppendLine(); - - if (NvApi.NvAPI_GPU_GetPCIIdentifiers != null) + try { - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetPCIIdentifiers(_handle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); - if (status == NvApi.NvStatus.OK) - { - r.Append("DeviceID: 0x"); - r.AppendLine(deviceId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("SubSystemID: 0x"); - r.AppendLine(subSystemId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("RevisionID: 0x"); - r.AppendLine(revisionId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("ExtDeviceID: 0x"); - r.AppendLine(extDeviceId.ToString("X", CultureInfo.InvariantCulture)); - r.AppendLine(); - } - } + GPUThermalSensor[] thermalSensors = _physicalGpu.ThermalInformation.ThermalSensors.ToArray(); - if (NvApi.NvAPI_GPU_GetThermalSettings != null) - { - NvApi.NvGPUThermalSettings settings = new() - { - Version = NvApi.GPU_THERMAL_SETTINGS_VER, Count = NvApi.MAX_THERMAL_SENSORS_PER_GPU, Sensor = new NvApi.NvSensor[NvApi.MAX_THERMAL_SENSORS_PER_GPU] - }; - - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.ALL, ref settings); r.AppendLine("Thermal Settings"); r.AppendLine(); - if (status == NvApi.NvStatus.OK) + + for (int i = 0; i < thermalSensors.Length; i++) { - for (int i = 0; i < settings.Count; i++) - { - r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i, settings.Sensor[i].Controller, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i, settings.Sensor[i].DefaultMinTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i, settings.Sensor[i].DefaultMaxTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i, settings.Sensor[i].CurrentTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i, settings.Sensor[i].Target, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); + r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i, thermalSensors[i].Target, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].SensorId: {1}{2}", i, thermalSensors[i].SensorId, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].DefaultMinimumTemperature: {1}{2}", i, thermalSensors[i].DefaultMinimumTemperature, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].DefaultMaximumTemperature: {1}{2}", i, thermalSensors[i].DefaultMaximumTemperature, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].CurrentTemperature: {1}{2}", i, thermalSensors[i].CurrentTemperature, Environment.NewLine); } r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - if (NvApi.NvAPI_GPU_GetAllClocks != null) + try { - NvApi.NvClocks allClocks = new() { Version = NvApi.GPU_CLOCKS_VER, Clock = new uint[NvApi.MAX_CLOCKS_PER_GPU] }; - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetAllClocks(_handle, ref allClocks); + KeyValuePair[] clocks = _physicalGpu.CurrentClockFrequencies.Clocks.OrderBy(x => x.Key).ToArray(); r.AppendLine("Clocks"); r.AppendLine(); - if (status == NvApi.NvStatus.OK) + + for (int i = 0; i < clocks.Length; i++) { - for (int i = 0; i < allClocks.Clock.Length; i++) - if (allClocks.Clock[i] > 0) - { - r.AppendFormat(" Clock[{0}]: {1}{2}", i, allClocks.Clock[i], Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); + KeyValuePair clock = clocks[i]; + r.AppendFormat(" Clock[{0}]: {1}{2}", i, clock, Environment.NewLine); } r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - if (NvApi.NvAPI_GPU_GetTachReading != null) + try { - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetTachReading(_handle, out int tachValue); + GPUCooler[] coolers = _physicalGpu.CoolerInformation.Coolers.ToArray(); - r.AppendLine("Tachometer"); + r.AppendLine("Coolers"); r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine); - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetPStates != null) - { - NvApi.NvPStates states = new() { Version = NvApi.GPU_PSTATES_VER, PStates = new NvApi.NvPState[NvApi.MAX_PSTATES_PER_GPU] }; - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetPStates(_handle, ref states); - - r.AppendLine("P-States"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) + if (coolers.Length > 0) { - for (int i = 0; i < states.PStates.Length; i++) + for (int i = 0; i < coolers.Length; i++) { - if (states.PStates[i].Present) - r.AppendFormat(" Percentage[{0}]: {1}{2}", i, states.PStates[i].Percentage, Environment.NewLine); + GPUCooler cooler = coolers[i]; + + r.AppendFormat(" Cooler[{0}].CoolerId: {1}{2}", i, cooler.CoolerId, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CoolerType: {1}{2}", i, cooler.CoolerType, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].ControlMode: {1}{2}", i, cooler.ControlMode, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i, cooler.CurrentPolicy, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i, cooler.CurrentLevel, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentFanSpeedInRPM: {1}{2}", i, cooler.CurrentFanSpeedInRPM, Environment.NewLine); } } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - if (NvApi.NvAPI_GPU_GetUsages != null) + try { - NvApi.NvUsages usages = new() { Version = NvApi.GPU_USAGES_VER, Usage = new uint[NvApi.MAX_USAGES_PER_GPU] }; - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetUsages(_handle, ref usages); + GPUUsageDomainStatus[] usages = _physicalGpu.UsageInformation.UtilizationDomainsStatus.ToArray(); r.AppendLine("Usages"); r.AppendLine(); - if (status == NvApi.NvStatus.OK) + + for (int i = 0; i < usages.Length; i++) { - for (int i = 0; i < usages.Usage.Length; i++) - { - if (usages.Usage[i] > 0) - r.AppendFormat(" Usage[{0}]: {1}{2}", i, usages.Usage[i], Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); + GPUUsageDomainStatus usage = usages[i]; + + r.AppendFormat(" Usage[{0}].Domain: {1}{2}", i, usage.Domain, Environment.NewLine); + r.AppendFormat(" Usage[{0}].Percentage: {1}{2}", i, usage.Percentage, Environment.NewLine); } r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } - if (NvApi.NvAPI_GPU_GetCoolerSettings != null) + try { - NvApi.NvGPUCoolerSettings settings = new() { Version = NvApi.GPU_COOLER_SETTINGS_VER, Cooler = new NvApi.NvCooler[NvApi.MAX_COOLER_PER_GPU] }; - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetCoolerSettings(_handle, 0, ref settings); - r.AppendLine("Cooler Settings"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < settings.Count; i++) - { - r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i, settings.Cooler[i].Type, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i, settings.Cooler[i].Controller, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i, settings.Cooler[i].DefaultMin, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i, settings.Cooler[i].DefaultMax, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i, settings.Cooler[i].CurrentMin, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i, settings.Cooler[i].CurrentMax, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i, settings.Cooler[i].CurrentLevel, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i, settings.Cooler[i].DefaultPolicy, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i, settings.Cooler[i].CurrentPolicy, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i, settings.Cooler[i].Target, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i, settings.Cooler[i].ControlType, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i, settings.Cooler[i].Active, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null) - { - var coolers = new NvApi.NvFanCoolersStatus { Version = NvApi.GPU_FAN_COOLERS_STATUS_VER, Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] }; - - NvApi.NvStatus status = NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers); - - r.AppendLine("Fan Coolers Status"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < coolers.Count; i++) - { - r.AppendFormat(" Items[{0}].Type: {1}{2}", - i, - coolers.Items[i].Type, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentRpm: {1}{2}", - i, - coolers.Items[i].CurrentRpm, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentMinLevel: {1}{2}", - i, - coolers.Items[i].CurrentMinLevel, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentMaxLevel: {1}{2}", - i, - coolers.Items[i].CurrentMaxLevel, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentLevel: {1}{2}", - i, - coolers.Items[i].CurrentLevel, - Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetMemoryInfo != null && _displayHandle.HasValue) - { - NvApi.NvMemoryInfo memoryInfo = new() { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetMemoryInfo(_displayHandle.Value, ref memoryInfo); + GPUMemoryInformation memoryInformation = _physicalGpu.MemoryInformation; r.AppendLine("Memory Info"); r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < memoryInfo.Values.Length; i++) - r.AppendFormat(" Value[{0}]: {1}{2}", i, memoryInfo.Values[i], Environment.NewLine); - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } + r.AppendFormat(" DedicatedVideoMemoryInkB: {0}{1}", memoryInformation.DedicatedVideoMemoryInkB, Environment.NewLine); + r.AppendFormat(" CurrentAvailableDedicatedVideoMemoryInkB: {0}{1}", memoryInformation.CurrentAvailableDedicatedVideoMemoryInkB, Environment.NewLine); + r.AppendFormat(" AvailableDedicatedVideoMemoryInkB: {0}{1}", memoryInformation.AvailableDedicatedVideoMemoryInkB, Environment.NewLine); r.AppendLine(); } + catch (Exception e) when (e is NVIDIAApiException or NVIDIANotSupportedException) + { } return r.ToString(); } private void SoftwareControlValueChanged(IControl control) { - NvApi.NvGPUCoolerLevels coolerLevels = new() { Version = NvApi.GPU_COOLER_LEVELS_VER, Levels = new NvApi.NvLevel[NvApi.MAX_COOLER_PER_GPU] }; - coolerLevels.Levels[0].Level = (int)control.SoftwareValue; - coolerLevels.Levels[0].Policy = 1; - NvApi.NvAPI_GPU_SetCoolerLevels(_handle, 0, ref coolerLevels); + int coolerId = -1; + int index = control.Sensor.Index; + + GPUCooler[] coolers = _physicalGpu.CoolerInformation.Coolers.ToArray(); + if (coolers.Length > index) + { + GPUCooler cooler = coolers[index]; + coolerId = cooler.CoolerId; + } + + _physicalGpu.CoolerInformation.SetCoolerSettings(coolerId, CoolerPolicy.Manual, (int)control.SoftwareValue); } private void ControlModeChanged(IControl control) @@ -732,33 +634,53 @@ namespace LibreHardwareMonitor.Hardware.Gpu switch (control.ControlMode) { case ControlMode.Undefined: + { return; + } case ControlMode.Default: - SetDefaultFanSpeed(); + { + RestoreDefaultFanBehavior(control.Sensor.Index); break; + } case ControlMode.Software: + { SoftwareControlValueChanged(control); break; + } default: + { return; + } } } - private void SetDefaultFanSpeed() + private void RestoreDefaultFanBehavior(int index) { - NvApi.NvGPUCoolerLevels coolerLevels = new() { Version = NvApi.GPU_COOLER_LEVELS_VER, Levels = new NvApi.NvLevel[NvApi.MAX_COOLER_PER_GPU] }; - coolerLevels.Levels[0].Policy = 0x20; - NvApi.NvAPI_GPU_SetCoolerLevels(_handle, 0, ref coolerLevels); + int coolerId = -1; + + GPUCooler[] coolers = _physicalGpu.CoolerInformation.Coolers.ToArray(); + if (coolers.Length > index) + { + GPUCooler cooler = coolers[index]; + coolerId = cooler.CoolerId; + } + + if (coolerId != -1) + _physicalGpu.CoolerInformation.RestoreCoolerSettingsToDefault(coolerId); } public override void Close() { - if (_fanControl != null) + if (_fanControls != null) { - _fanControl.ControlModeChanged -= ControlModeChanged; - _fanControl.SoftwareControlValueChanged -= SoftwareControlValueChanged; - if (_fanControl.ControlMode != ControlMode.Undefined) - SetDefaultFanSpeed(); + for (int i = 0; i < _fanControls.Length; i++) + { + _fanControls[i].ControlModeChanged -= ControlModeChanged; + _fanControls[i].SoftwareControlValueChanged -= SoftwareControlValueChanged; + + if (_fanControls[i].ControlMode != ControlMode.Undefined) + RestoreDefaultFanBehavior(i); + } } base.Close(); diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs index b515f5b..88c4968 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs @@ -4,10 +4,14 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. +using System; using System.Collections.Generic; using System.Globalization; using System.Text; using LibreHardwareMonitor.Interop; +using NvAPIWrapper; +using NvAPIWrapper.GPU; +using NvAPIWrapper.Native.Exceptions; namespace LibreHardwareMonitor.Hardware.Gpu { @@ -15,72 +19,66 @@ namespace LibreHardwareMonitor.Hardware.Gpu { private readonly List _hardware = new(); private readonly StringBuilder _report = new(); + private readonly bool _initialized; public NvidiaGroup(ISettings settings) { - if (!NvApi.IsAvailable) - return; - - _report.AppendLine("NvApi"); _report.AppendLine(); - if (NvApi.NvAPI_GetInterfaceVersionString(out string version) == NvApi.NvStatus.OK) + try { + NVIDIA.Initialize(); + _initialized = true; + } + catch (Exception e) when (e is NVIDIAApiException or DllNotFoundException) + { + // No NVIDIA devices. + return; + } + + try + { + string interfaceVersion = NVIDIA.InterfaceVersionString; + _report.Append("Version: "); - _report.AppendLine(version); + _report.AppendLine(interfaceVersion); } + catch (NVIDIAApiException) + { } - NvApi.NvPhysicalGpuHandle[] handles = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; - if (NvApi.NvAPI_EnumPhysicalGPUs == null) + try { - _report.AppendLine("Error: NvAPI_EnumPhysicalGPUs not available"); - _report.AppendLine(); - return; + string driverVersion = NVIDIA.DriverVersion.ToString(); + + _report.Append("Driver: "); + _report.AppendLine(driverVersion); } + catch (NVIDIAApiException) + { } - NvApi.NvStatus status = NvApi.NvAPI_EnumPhysicalGPUs(handles, out int count); - if (status != NvApi.NvStatus.OK) + try { - _report.AppendLine("Status: " + status); - _report.AppendLine(); - return; + string driverBranch = NVIDIA.DriverBranchVersion; + + _report.Append("Driver branch: "); + _report.AppendLine(driverBranch); } + catch (NVIDIAApiException) + { } - IDictionary displayHandles = new Dictionary(); - if (NvApi.NvAPI_EnumNvidiaDisplayHandle != null && NvApi.NvAPI_GetPhysicalGPUsFromDisplay != null) + try { - status = NvApi.NvStatus.OK; - int i = 0; - while (status == NvApi.NvStatus.OK) - { - NvApi.NvDisplayHandle displayHandle = new(); - status = NvApi.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle); - i++; - - if (status == NvApi.NvStatus.OK) - { - NvApi.NvPhysicalGpuHandle[] handlesFromDisplay = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; - if (NvApi.NvAPI_GetPhysicalGPUsFromDisplay(displayHandle, handlesFromDisplay, out uint countFromDisplay) == NvApi.NvStatus.OK) - { - for (int j = 0; j < countFromDisplay; j++) - { - if (!displayHandles.ContainsKey(handlesFromDisplay[j])) - displayHandles.Add(handlesFromDisplay[j], displayHandle); - } - } - } - } - } + PhysicalGPU[] physicalGpus = PhysicalGPU.GetPhysicalGPUs(); - _report.Append("Number of GPUs: "); - _report.AppendLine(count.ToString(CultureInfo.InvariantCulture)); + _report.Append("Number of GPUs: "); + _report.AppendLine(physicalGpus.Length.ToString(CultureInfo.InvariantCulture)); - for (int i = 0; i < count; i++) - { - displayHandles.TryGetValue(handles[i], out NvApi.NvDisplayHandle displayHandle); - _hardware.Add(new NvidiaGpu(i, handles[i], displayHandle, settings)); + for (int i = 0; i < physicalGpus.Length; i++) + _hardware.Add(new NvidiaGpu(i, physicalGpus[i], settings)); } + catch (NVIDIAApiException) + { } _report.AppendLine(); } @@ -94,10 +92,21 @@ namespace LibreHardwareMonitor.Hardware.Gpu public void Close() { + if (!_initialized) + return; + + foreach (Hardware gpu in _hardware) gpu.Close(); NvidiaML.Close(); + + try + { + NVIDIA.Unload(); + } + catch (Exception e) when (e is NVIDIAApiException or DllNotFoundException) + { } } } } diff --git a/LibreHardwareMonitorLib/Hardware/IControl.cs b/LibreHardwareMonitorLib/Hardware/IControl.cs index 23cf096..d8645c6 100644 --- a/LibreHardwareMonitorLib/Hardware/IControl.cs +++ b/LibreHardwareMonitorLib/Hardware/IControl.cs @@ -23,6 +23,8 @@ namespace LibreHardwareMonitor.Hardware float MinSoftwareValue { get; } + ISensor Sensor { get; } + float SoftwareValue { get; } void SetDefault(); diff --git a/LibreHardwareMonitorLib/Interop/NvApi.cs b/LibreHardwareMonitorLib/Interop/NvApi.cs deleted file mode 100644 index 8c53cf4..0000000 --- a/LibreHardwareMonitorLib/Interop/NvApi.cs +++ /dev/null @@ -1,440 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. -// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -// Copyright (C) LibreHardwareMonitor and Contributors. -// All Rights Reserved. - -using System; -using System.Runtime.InteropServices; -using System.Text; - -// ReSharper disable InconsistentNaming - -namespace LibreHardwareMonitor.Interop -{ - internal static class NvApi - { - public const int MAX_CLOCKS_PER_GPU = 0x120; - public const int MAX_COOLER_PER_GPU = 20; - public const int MAX_FAN_COOLERS_STATUS_ITEMS = 32; - public const int MAX_MEMORY_VALUES_PER_GPU = 5; - public const int MAX_PHYSICAL_GPUS = 64; - public const int MAX_PSTATES_PER_GPU = 8; - public const int MAX_THERMAL_SENSORS_PER_GPU = 3; - public const int MAX_USAGES_PER_GPU = 33; - public const int SHORT_STRING_MAX = 64; - - public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint)Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000; - public static readonly uint GPU_CLOCKS_VER = (uint)Marshal.SizeOf(typeof(NvClocks)) | 0x20000; - public static readonly uint GPU_COOLER_LEVELS_VER = (uint)Marshal.SizeOf(typeof(NvGPUCoolerLevels)) | 0x10000; - public static readonly uint GPU_COOLER_SETTINGS_VER = (uint)Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000; - public static readonly uint GPU_MEMORY_INFO_VER = (uint)Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000; - public static readonly uint GPU_PSTATES_VER = (uint)Marshal.SizeOf(typeof(NvPStates)) | 0x10000; - public static readonly uint GPU_THERMAL_SETTINGS_VER = (uint)Marshal.SizeOf(typeof(NvGPUThermalSettings)) | 0x10000; - public static readonly uint GPU_USAGES_VER = (uint)Marshal.SizeOf(typeof(NvUsages)) | 0x10000; - public static readonly uint GPU_FAN_COOLERS_STATUS_VER = (uint)Marshal.SizeOf(typeof(NvFanCoolersStatus)) | 0x10000; - - public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate NvAPI_EnumNvidiaDisplayHandle; - public static readonly NvAPI_EnumPhysicalGPUsDelegate NvAPI_EnumPhysicalGPUs; - public static readonly NvAPI_GetDisplayDriverVersionDelegate NvAPI_GetDisplayDriverVersion; - public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate NvAPI_GetPhysicalGPUsFromDisplay; - public static readonly NvAPI_GPU_GetAllClocksDelegate NvAPI_GPU_GetAllClocks; - public static readonly NvAPI_GPU_GetBusIdDelegate NvAPI_GPU_GetBusId; - public static readonly NvAPI_GPU_GetCoolerSettingsDelegate NvAPI_GPU_GetCoolerSettings; - public static readonly NvAPI_GPU_GetMemoryInfoDelegate NvAPI_GPU_GetMemoryInfo; - public static readonly NvAPI_GPU_GetPCIIdentifiersDelegate NvAPI_GPU_GetPCIIdentifiers; - public static readonly NvAPI_GPU_GetPStatesDelegate NvAPI_GPU_GetPStates; - public static readonly NvAPI_GPU_GetTachReadingDelegate NvAPI_GPU_GetTachReading; - public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; - public static readonly NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages; - public static readonly NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels; - public static readonly NvAPI_GPU_ClientFanCoolersGetStatusDelegate NvAPI_GPU_ClientFanCoolersGetStatus; - - private static readonly NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; - private static readonly NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; - - static NvApi() - { - NvAPI_InitializeDelegate nvApiInitialize; - - try - { - GetDelegate(0x0150E828, out nvApiInitialize); - } - catch (DllNotFoundException) - { - return; - } - catch (EntryPointNotFoundException) - { - return; - } - catch (ArgumentNullException) - { - return; - } - - if (nvApiInitialize() == NvStatus.OK) - { - GetDelegate(0xE3640A56, out NvAPI_GPU_GetThermalSettings); - GetDelegate(0xCEEE8E9F, out _nvAPI_GPU_GetFullName); - GetDelegate(0x9ABDD40D, out NvAPI_EnumNvidiaDisplayHandle); - GetDelegate(0x34EF9506, out NvAPI_GetPhysicalGPUsFromDisplay); - GetDelegate(0xE5AC921F, out NvAPI_EnumPhysicalGPUs); - GetDelegate(0x5F608315, out NvAPI_GPU_GetTachReading); - GetDelegate(0x1BD69F49, out NvAPI_GPU_GetAllClocks); - GetDelegate(0x60DED2ED, out NvAPI_GPU_GetPStates); - GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages); - GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings); - GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels); - GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo); - GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion); - GetDelegate(0x01053FA5, out _nvAPI_GetInterfaceVersionString); - GetDelegate(0x2DDFB66E, out NvAPI_GPU_GetPCIIdentifiers); - GetDelegate(0x1BE0B8E5, out NvAPI_GPU_GetBusId); - GetDelegate(0x35AED5E8, out NvAPI_GPU_ClientFanCoolersGetStatus); - - IsAvailable = true; - } - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion nvDisplayDriverVersion); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(StringBuilder version); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetBusIdDelegate(NvPhysicalGpuHandle gpuHandle, out uint busId); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerSettings nvGPUCoolerSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetPStatesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvPStates nvPStates); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(NvPhysicalGpuHandle gpuHandle, out int value); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvGPUThermalSettings nvGPUThermalSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerLevels NvGPUCoolerLevels); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolersStatus fanCoolersStatus); - - public static bool IsAvailable { get; } - - [DllImport(@"nvapi.dll", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] - private static extern IntPtr NvAPI32_QueryInterface(uint interfaceId); - - [DllImport(@"nvapi64.dll", EntryPoint = @"nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] - private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); - - public static NvStatus NvAPI_GPU_GetFullName(NvPhysicalGpuHandle gpuHandle, out string name) - { - StringBuilder builder = new StringBuilder(SHORT_STRING_MAX); - NvStatus status = _nvAPI_GPU_GetFullName?.Invoke(gpuHandle, builder) ?? NvStatus.FUNCTION_NOT_FOUND; - - name = builder.ToString(); - return status; - } - - public static NvStatus NvAPI_GetInterfaceVersionString(out string version) - { - StringBuilder builder = new StringBuilder(SHORT_STRING_MAX); - NvStatus status = _nvAPI_GetInterfaceVersionString?.Invoke(builder) ?? NvStatus.FUNCTION_NOT_FOUND; - - version = builder.ToString(); - return status; - } - - private static void GetDelegate(uint id, out T newDelegate) where T : class - { - IntPtr ptr = IntPtr.Size == 4 ? NvAPI32_QueryInterface(id) : NvAPI64_QueryInterface(id); - - if (ptr != IntPtr.Zero) - newDelegate = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; - else - newDelegate = null; - } - - internal enum NvStatus - { - OK = 0, - ERROR = -1, - LIBRARY_NOT_FOUND = -2, - NO_IMPLEMENTATION = -3, - API_NOT_INTIALIZED = -4, - INVALID_ARGUMENT = -5, - NVIDIA_DEVICE_NOT_FOUND = -6, - END_ENUMERATION = -7, - INVALID_HANDLE = -8, - INCOMPATIBLE_STRUCT_VERSION = -9, - HANDLE_INVALIDATED = -10, - OPENGL_CONTEXT_NOT_CURRENT = -11, - NO_GL_EXPERT = -12, - INSTRUMENTATION_DISABLED = -13, - EXPECTED_LOGICAL_GPU_HANDLE = -100, - EXPECTED_PHYSICAL_GPU_HANDLE = -101, - EXPECTED_DISPLAY_HANDLE = -102, - INVALID_COMBINATION = -103, - NOT_SUPPORTED = -104, - PORTID_NOT_FOUND = -105, - EXPECTED_UNATTACHED_DISPLAY_HANDLE = -106, - INVALID_PERF_LEVEL = -107, - DEVICE_BUSY = -108, - NV_PERSIST_FILE_NOT_FOUND = -109, - PERSIST_DATA_NOT_FOUND = -110, - EXPECTED_TV_DISPLAY = -111, - EXPECTED_TV_DISPLAY_ON_DCONNECTOR = -112, - NO_ACTIVE_SLI_TOPOLOGY = -113, - SLI_RENDERING_MODE_NOTALLOWED = -114, - EXPECTED_DIGITAL_FLAT_PANEL = -115, - ARGUMENT_EXCEED_MAX_SIZE = -116, - DEVICE_SWITCHING_NOT_ALLOWED = -117, - TESTING_CLOCKS_NOT_SUPPORTED = -118, - UNKNOWN_UNDERSCAN_CONFIG = -119, - TIMEOUT_RECONFIGURING_GPU_TOPO = -120, - DATA_NOT_FOUND = -121, - EXPECTED_ANALOG_DISPLAY = -122, - NO_VIDLINK = -123, - REQUIRES_REBOOT = -124, - INVALID_HYBRID_MODE = -125, - MIXED_TARGET_TYPES = -126, - SYSWOW64_NOT_SUPPORTED = -127, - IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED = -128, - REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS = -129, - OUT_OF_MEMORY = -130, - WAS_STILL_DRAWING = -131, - FILE_NOT_FOUND = -132, - TOO_MANY_UNIQUE_STATE_OBJECTS = -133, - INVALID_CALL = -134, - D3D10_1_LIBRARY_NOT_FOUND = -135, - FUNCTION_NOT_FOUND = -136 - } - - internal enum NvThermalController - { - NONE = 0, - GPU_INTERNAL, - ADM1032, - MAX6649, - MAX1617, - LM99, - LM89, - LM64, - ADT7473, - SBMAX6649, - VBIOSEVT, - OS, - UNKNOWN = -1 - } - - internal enum NvThermalTarget - { - NONE = 0, - GPU = 1, - MEMORY = 2, - POWER_SUPPLY = 4, - BOARD = 8, - ALL = 15, - UNKNOWN = -1 - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvSensor - { - public NvThermalController Controller; - public uint DefaultMinTemp; - public uint DefaultMaxTemp; - public uint CurrentTemp; - public NvThermalTarget Target; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvGPUThermalSettings - { - public uint Version; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_THERMAL_SENSORS_PER_GPU)] - public NvSensor[] Sensor; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NvDisplayHandle - { - private readonly IntPtr ptr; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NvPhysicalGpuHandle - { - private readonly IntPtr ptr; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvClocks - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_CLOCKS_PER_GPU)] - public uint[] Clock; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvPState - { - public bool Present; - public int Percentage; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvPStates - { - public uint Version; - public uint Flags; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PSTATES_PER_GPU)] - public NvPState[] PStates; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvUsages - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_USAGES_PER_GPU)] - public uint[] Usage; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvCooler - { - public int Type; - public int Controller; - public int DefaultMin; - public int DefaultMax; - public int CurrentMin; - public int CurrentMax; - public int CurrentLevel; - public int DefaultPolicy; - public int CurrentPolicy; - public int Target; - public int ControlType; - public int Active; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolersStatus - { - public uint Version; - public uint Count; - - public ulong Reserved1; - public ulong Reserved2; - public ulong Reserved3; - public ulong Reserved4; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_COOLERS_STATUS_ITEMS)] - internal NvFanCoolersStatusItem[] Items; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolersStatusItem - { - public uint Type; - public uint CurrentRpm; - public uint CurrentMinLevel; - public uint CurrentMaxLevel; - public uint CurrentLevel; - - public uint Reserved1; - public uint Reserved2; - public uint Reserved3; - public uint Reserved4; - public uint Reserved5; - public uint Reserved6; - public uint Reserved7; - public uint Reserved8; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvGPUCoolerSettings - { - public uint Version; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLER_PER_GPU)] - public NvCooler[] Cooler; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvLevel - { - public int Level; - public int Policy; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvGPUCoolerLevels - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLER_PER_GPU)] - public NvLevel[] Levels; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvMemoryInfo - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_MEMORY_VALUES_PER_GPU)] - public uint[] Values; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvDisplayDriverVersion - { - public uint Version; - public uint DriverVersion; - public uint BldChangeListNum; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] - public string BuildBranch; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] - public string Adapter; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate NvStatus NvAPI_InitializeDelegate(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(NvPhysicalGpuHandle gpuHandle, StringBuilder name); - } -} diff --git a/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj b/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj index ad0722f..b711925 100644 --- a/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj +++ b/LibreHardwareMonitorLib/LibreHardwareMonitorLib.csproj @@ -42,6 +42,7 @@ +