Added fan control for Nvidia GPUs based on a patch by Christian Valli?res.
1.1 --- a/Hardware/Nvidia/NVAPI.cs Thu Jul 07 20:41:09 2011 +0000
1.2 +++ b/Hardware/Nvidia/NVAPI.cs Thu Jul 07 21:53:09 2011 +0000
1.3 @@ -16,10 +16,11 @@
1.4
1.5 The Initial Developer of the Original Code is
1.6 Michael Möller <m.moeller@gmx.ch>.
1.7 - Portions created by the Initial Developer are Copyright (C) 2009-2010
1.8 + Portions created by the Initial Developer are Copyright (C) 2009-2011
1.9 the Initial Developer. All Rights Reserved.
1.10
1.11 Contributor(s):
1.12 + Christian Vallières
1.13
1.14 Alternatively, the contents of this file may be used under the terms of
1.15 either the GNU General Public License Version 2 or later (the "GPL"), or
1.16 @@ -97,17 +98,17 @@
1.17
1.18 internal enum NvThermalController {
1.19 NONE = 0,
1.20 - GPU_INTERNAL,
1.21 + GPU_INTERNAL,
1.22 ADM1032,
1.23 - MAX6649,
1.24 - MAX1617,
1.25 - LM99,
1.26 - LM89,
1.27 - LM64,
1.28 + MAX6649,
1.29 + MAX1617,
1.30 + LM99,
1.31 + LM89,
1.32 + LM64,
1.33 ADT7473,
1.34 SBMAX6649,
1.35 - VBIOSEVT,
1.36 - OS,
1.37 + VBIOSEVT,
1.38 + OS,
1.39 UNKNOWN = -1,
1.40 }
1.41
1.42 @@ -127,14 +128,14 @@
1.43 public uint DefaultMinTemp;
1.44 public uint DefaultMaxTemp;
1.45 public uint CurrentTemp;
1.46 - public NvThermalTarget Target;
1.47 + public NvThermalTarget Target;
1.48 }
1.49
1.50 [StructLayout(LayoutKind.Sequential, Pack = 8)]
1.51 internal struct NvGPUThermalSettings {
1.52 public uint Version;
1.53 public uint Count;
1.54 - [MarshalAs(UnmanagedType.ByValArray,
1.55 + [MarshalAs(UnmanagedType.ByValArray,
1.56 SizeConst = NVAPI.MAX_THERMAL_SENSORS_PER_GPU)]
1.57 public NvSensor[] Sensor;
1.58 }
1.59 @@ -202,9 +203,22 @@
1.60 }
1.61
1.62 [StructLayout(LayoutKind.Sequential, Pack = 8)]
1.63 + internal struct NvLevel {
1.64 + public int Level;
1.65 + public int Policy;
1.66 + }
1.67 +
1.68 + [StructLayout(LayoutKind.Sequential, Pack = 8)]
1.69 + internal struct NvGPUCoolerLevels {
1.70 + public uint Version;
1.71 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_COOLER_PER_GPU)]
1.72 + public NvLevel[] Levels;
1.73 + }
1.74 +
1.75 + [StructLayout(LayoutKind.Sequential, Pack = 8)]
1.76 internal struct NvMemoryInfo {
1.77 public uint Version;
1.78 - [MarshalAs(UnmanagedType.ByValArray, SizeConst =
1.79 + [MarshalAs(UnmanagedType.ByValArray, SizeConst =
1.80 NVAPI.MAX_MEMORY_VALUES_PER_GPU)]
1.81 public uint[] Values;
1.82 }
1.83 @@ -225,7 +239,7 @@
1.84 public const int MAX_PHYSICAL_GPUS = 64;
1.85 public const int SHORT_STRING_MAX = 64;
1.86
1.87 - public const int MAX_THERMAL_SENSORS_PER_GPU = 3;
1.88 + public const int MAX_THERMAL_SENSORS_PER_GPU = 3;
1.89 public const int MAX_CLOCKS_PER_GPU = 0x120;
1.90 public const int MAX_PSTATES_PER_GPU = 8;
1.91 public const int MAX_USAGES_PER_GPU = 33;
1.92 @@ -242,23 +256,25 @@
1.93 Marshal.SizeOf(typeof(NvUsages)) | 0x10000;
1.94 public static readonly uint GPU_COOLER_SETTINGS_VER = (uint)
1.95 Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000;
1.96 - public static readonly uint GPU_MEMORY_INFO_VER = (uint)
1.97 + public static readonly uint GPU_MEMORY_INFO_VER = (uint)
1.98 Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000;
1.99 public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint)
1.100 Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000;
1.101 -
1.102 + public static readonly uint GPU_COOLER_LEVELS_VER = (uint)
1.103 + Marshal.SizeOf(typeof(NvGPUCoolerLevels)) | 0x10000;
1.104 +
1.105 private delegate IntPtr nvapi_QueryInterfaceDelegate(uint id);
1.106 private delegate NvStatus NvAPI_InitializeDelegate();
1.107 private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(
1.108 NvPhysicalGpuHandle gpuHandle, StringBuilder name);
1.109
1.110 public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(
1.111 - NvPhysicalGpuHandle gpuHandle, int sensorIndex,
1.112 + NvPhysicalGpuHandle gpuHandle, int sensorIndex,
1.113 ref NvGPUThermalSettings nvGPUThermalSettings);
1.114 public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum,
1.115 ref NvDisplayHandle displayHandle);
1.116 public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(
1.117 - NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles,
1.118 + NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles,
1.119 out uint gpuCount);
1.120 public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate(
1.121 [Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
1.122 @@ -273,6 +289,9 @@
1.123 public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(
1.124 NvPhysicalGpuHandle gpuHandle, int coolerIndex,
1.125 ref NvGPUCoolerSettings nvGPUCoolerSettings);
1.126 + public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(
1.127 + NvPhysicalGpuHandle gpuHandle, int coolerIndex,
1.128 + ref NvGPUCoolerLevels NvGPUCoolerLevels);
1.129 public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(
1.130 NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo);
1.131 public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(
1.132 @@ -284,12 +303,12 @@
1.133 private static readonly bool available;
1.134 private static readonly nvapi_QueryInterfaceDelegate nvapi_QueryInterface;
1.135 private static readonly NvAPI_InitializeDelegate NvAPI_Initialize;
1.136 - private static readonly NvAPI_GPU_GetFullNameDelegate
1.137 + private static readonly NvAPI_GPU_GetFullNameDelegate
1.138 _NvAPI_GPU_GetFullName;
1.139 private static readonly NvAPI_GetInterfaceVersionStringDelegate
1.140 _NvAPI_GetInterfaceVersionString;
1.141
1.142 - public static readonly NvAPI_GPU_GetThermalSettingsDelegate
1.143 + public static readonly NvAPI_GPU_GetThermalSettingsDelegate
1.144 NvAPI_GPU_GetThermalSettings;
1.145 public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate
1.146 NvAPI_EnumNvidiaDisplayHandle;
1.147 @@ -307,6 +326,8 @@
1.148 NvAPI_GPU_GetUsages;
1.149 public static readonly NvAPI_GPU_GetCoolerSettingsDelegate
1.150 NvAPI_GPU_GetCoolerSettings;
1.151 + public static readonly NvAPI_GPU_SetCoolerLevelsDelegate
1.152 + NvAPI_GPU_SetCoolerLevels;
1.153 public static readonly NvAPI_GPU_GetMemoryInfoDelegate
1.154 NvAPI_GPU_GetMemoryInfo;
1.155 public static readonly NvAPI_GetDisplayDriverVersionDelegate
1.156 @@ -345,9 +366,8 @@
1.157 }
1.158 }
1.159
1.160 - private static void GetDelegate<T>(uint id, out T newDelegate)
1.161 - where T : class
1.162 - {
1.163 + private static void GetDelegate<T>(uint id, out T newDelegate)
1.164 + where T : class {
1.165 IntPtr ptr = nvapi_QueryInterface(id);
1.166 if (ptr != IntPtr.Zero) {
1.167 newDelegate =
1.168 @@ -357,7 +377,7 @@
1.169 }
1.170 }
1.171
1.172 - static NVAPI() {
1.173 + static NVAPI() {
1.174 DllImportAttribute attribute = new DllImportAttribute(GetDllName());
1.175 attribute.CallingConvention = CallingConvention.Cdecl;
1.176 attribute.PreserveSig = true;
1.177 @@ -382,6 +402,7 @@
1.178 GetDelegate(0x60DED2ED, out NvAPI_GPU_GetPStates);
1.179 GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);
1.180 GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings);
1.181 + GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels);
1.182 GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo);
1.183 GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion);
1.184 GetDelegate(0x01053FA5, out _NvAPI_GetInterfaceVersionString);
2.1 --- a/Hardware/Nvidia/NvidiaGPU.cs Thu Jul 07 20:41:09 2011 +0000
2.2 +++ b/Hardware/Nvidia/NvidiaGPU.cs Thu Jul 07 21:53:09 2011 +0000
2.3 @@ -20,6 +20,7 @@
2.4 the Initial Developer. All Rights Reserved.
2.5
2.6 Contributor(s):
2.7 + Christian Vallières
2.8
2.9 Alternatively, the contents of this file may be used under the terms of
2.10 either the GNU General Public License Version 2 or later (the "GPL"), or
2.11 @@ -52,12 +53,15 @@
2.12 private readonly Sensor[] loads;
2.13 private readonly Sensor control;
2.14 private readonly Sensor memoryLoad;
2.15 + private readonly Control fanControl;
2.16
2.17 - public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
2.18 - NvDisplayHandle? displayHandle, ISettings settings)
2.19 - : base(GetName(handle), new Identifier("nvidiagpu",
2.20 - adapterIndex.ToString(CultureInfo.InvariantCulture)), settings)
2.21 - {
2.22 + private bool restoreDefaultFanSpeedRequired;
2.23 + private NvLevel initialFanSpeedValue;
2.24 +
2.25 + public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
2.26 + NvDisplayHandle? displayHandle, ISettings settings)
2.27 + : base(GetName(handle), new Identifier("nvidiagpu",
2.28 + adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) {
2.29 this.adapterIndex = adapterIndex;
2.30 this.handle = handle;
2.31 this.displayHandle = displayHandle;
2.32 @@ -103,6 +107,18 @@
2.33 memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
2.34
2.35 control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
2.36 +
2.37 + NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
2.38 + if (coolerSettings.Count > 0) {
2.39 + fanControl = new Control(control, settings,
2.40 + coolerSettings.Cooler[0].DefaultMin,
2.41 + coolerSettings.Cooler[0].DefaultMax);
2.42 + fanControl.ControlModeChanged += ControlModeChanged;
2.43 + fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
2.44 + ControlModeChanged(fanControl);
2.45 + control.Control = fanControl;
2.46 + }
2.47 + Update();
2.48 }
2.49
2.50 private static string GetName(NvPhysicalGpuHandle handle) {
2.51 @@ -123,12 +139,26 @@
2.52 settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
2.53 settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
2.54 settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
2.55 - if (NVAPI.NvAPI_GPU_GetThermalSettings != null &&
2.56 + if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
2.57 NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
2.58 - ref settings) != NvStatus.OK) {
2.59 - settings.Count = 0;
2.60 + ref settings) == NvStatus.OK))
2.61 + {
2.62 + settings.Count = 0;
2.63 + }
2.64 + return settings;
2.65 + }
2.66 +
2.67 + private NvGPUCoolerSettings GetCoolerSettings() {
2.68 + NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
2.69 + settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
2.70 + settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
2.71 + if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
2.72 + NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0,
2.73 + ref settings) == NvStatus.OK))
2.74 + {
2.75 + settings.Count = 0;
2.76 }
2.77 - return settings;
2.78 + return settings;
2.79 }
2.80
2.81 private uint[] GetClocks() {
2.82 @@ -144,7 +174,7 @@
2.83
2.84 public override void Update() {
2.85 NvGPUThermalSettings settings = GetThermalSettings();
2.86 - foreach (Sensor sensor in temperatures)
2.87 + foreach (Sensor sensor in temperatures)
2.88 sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
2.89
2.90 if (fan != null) {
2.91 @@ -167,7 +197,7 @@
2.92 NvPStates states = new NvPStates();
2.93 states.Version = NVAPI.GPU_PSTATES_VER;
2.94 states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
2.95 - if (NVAPI.NvAPI_GPU_GetPStates != null &&
2.96 + if (NVAPI.NvAPI_GPU_GetPStates != null &&
2.97 NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
2.98 for (int i = 0; i < 3; i++)
2.99 if (states.PStates[i].Present) {
2.100 @@ -188,12 +218,9 @@
2.101 }
2.102 }
2.103
2.104 - NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings();
2.105 - coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
2.106 - coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
2.107 - if (NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
2.108 - NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) ==
2.109 - NvStatus.OK && coolerSettings.Count > 0) {
2.110 +
2.111 + NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
2.112 + if (coolerSettings.Count > 0) {
2.113 control.Value = coolerSettings.Cooler[0].CurrentLevel;
2.114 ActivateSensor(control);
2.115 }
2.116 @@ -202,9 +229,8 @@
2.117 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
2.118 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
2.119 if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
2.120 - NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
2.121 - NvStatus.OK)
2.122 - {
2.123 + NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
2.124 + NvStatus.OK) {
2.125 uint totalMemory = memoryInfo.Values[0];
2.126 uint freeMemory = memoryInfo.Values[4];
2.127 float usedMemory = Math.Max(totalMemory - freeMemory, 0);
2.128 @@ -221,9 +247,8 @@
2.129
2.130 r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
2.131 r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
2.132 -
2.133 - if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null)
2.134 - {
2.135 +
2.136 + if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) {
2.137 NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
2.138 driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
2.139 if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
2.140 @@ -231,7 +256,7 @@
2.141 r.Append("Driver Version: ");
2.142 r.Append(driverVersion.DriverVersion / 100);
2.143 r.Append(".");
2.144 - r.Append((driverVersion.DriverVersion % 100).ToString("00",
2.145 + r.Append((driverVersion.DriverVersion % 100).ToString("00",
2.146 CultureInfo.InvariantCulture));
2.147 r.AppendLine();
2.148 r.Append("Driver Branch: ");
2.149 @@ -269,7 +294,7 @@
2.150 r.AppendLine(status.ToString());
2.151 }
2.152 r.AppendLine();
2.153 - }
2.154 + }
2.155
2.156 if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
2.157 NvClocks allClocks = new NvClocks();
2.158 @@ -290,10 +315,10 @@
2.159 r.AppendLine(status.ToString());
2.160 }
2.161 r.AppendLine();
2.162 - }
2.163 -
2.164 + }
2.165 +
2.166 if (NVAPI.NvAPI_GPU_GetTachReading != null) {
2.167 - int tachValue;
2.168 + int tachValue;
2.169 NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
2.170
2.171 r.AppendLine("Tachometer");
2.172 @@ -332,7 +357,7 @@
2.173 usages.Version = NVAPI.GPU_USAGES_VER;
2.174 usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
2.175 NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
2.176 -
2.177 +
2.178 r.AppendLine("Usages");
2.179 r.AppendLine();
2.180 if (status == NvStatus.OK) {
2.181 @@ -394,7 +419,7 @@
2.182 NvMemoryInfo memoryInfo = new NvMemoryInfo();
2.183 memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
2.184 memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
2.185 - NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
2.186 + NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
2.187 ref memoryInfo);
2.188
2.189 r.AppendLine("Memory Info");
2.190 @@ -412,5 +437,45 @@
2.191
2.192 return r.ToString();
2.193 }
2.194 +
2.195 + private void SoftwareControlValueChanged(IControl control) {
2.196 + SaveDefaultFanSpeed();
2.197 + NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
2.198 + coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
2.199 + coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
2.200 + coolerLevels.Levels[0].Level = (int)control.SoftwareValue;
2.201 + coolerLevels.Levels[0].Policy = 1;
2.202 + NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
2.203 + }
2.204 +
2.205 + private void SaveDefaultFanSpeed() {
2.206 + if (!restoreDefaultFanSpeedRequired) {
2.207 + NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
2.208 + if (coolerSettings.Count > 0) {
2.209 + restoreDefaultFanSpeedRequired = true;
2.210 + initialFanSpeedValue.Level = coolerSettings.Cooler[0].CurrentLevel;
2.211 + initialFanSpeedValue.Policy = coolerSettings.Cooler[0].CurrentPolicy;
2.212 + }
2.213 + }
2.214 + }
2.215 +
2.216 + private void ControlModeChanged(IControl control) {
2.217 + if (control.ControlMode == ControlMode.Default) {
2.218 + RestoreDefaultFanSpeed();
2.219 + } else {
2.220 + SoftwareControlValueChanged(control);
2.221 + }
2.222 + }
2.223 +
2.224 + private void RestoreDefaultFanSpeed() {
2.225 + if (restoreDefaultFanSpeedRequired) {
2.226 + NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
2.227 + coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
2.228 + coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
2.229 + coolerLevels.Levels[0] = initialFanSpeedValue;
2.230 + NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
2.231 + restoreDefaultFanSpeedRequired = false;
2.232 + }
2.233 + }
2.234 }
2.235 }