# HG changeset patch # User moel.mich # Date 1310075589 0 # Node ID 65a1ae21325d115815bafb7fdcec3d34adc2e5ee # Parent d882720734bff66cc389b6b07c69c0261dc7893d Added fan control for Nvidia GPUs based on a patch by Christian Valli?res. diff -r d882720734bf -r 65a1ae21325d Hardware/Nvidia/NVAPI.cs --- a/Hardware/Nvidia/NVAPI.cs Thu Jul 07 20:41:09 2011 +0000 +++ b/Hardware/Nvidia/NVAPI.cs Thu Jul 07 21:53:09 2011 +0000 @@ -16,10 +16,11 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): + Christian Vallières Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or @@ -97,17 +98,17 @@ internal enum NvThermalController { NONE = 0, - GPU_INTERNAL, + GPU_INTERNAL, ADM1032, - MAX6649, - MAX1617, - LM99, - LM89, - LM64, + MAX6649, + MAX1617, + LM99, + LM89, + LM64, ADT7473, SBMAX6649, - VBIOSEVT, - OS, + VBIOSEVT, + OS, UNKNOWN = -1, } @@ -127,14 +128,14 @@ public uint DefaultMinTemp; public uint DefaultMaxTemp; public uint CurrentTemp; - public NvThermalTarget Target; + public NvThermalTarget Target; } [StructLayout(LayoutKind.Sequential, Pack = 8)] internal struct NvGPUThermalSettings { public uint Version; public uint Count; - [MarshalAs(UnmanagedType.ByValArray, + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_THERMAL_SENSORS_PER_GPU)] public NvSensor[] Sensor; } @@ -202,9 +203,22 @@ } [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 = NVAPI.MAX_COOLER_PER_GPU)] + public NvLevel[] Levels; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] internal struct NvMemoryInfo { public uint Version; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = + [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_MEMORY_VALUES_PER_GPU)] public uint[] Values; } @@ -225,7 +239,7 @@ public const int MAX_PHYSICAL_GPUS = 64; public const int SHORT_STRING_MAX = 64; - public const int MAX_THERMAL_SENSORS_PER_GPU = 3; + public const int MAX_THERMAL_SENSORS_PER_GPU = 3; public const int MAX_CLOCKS_PER_GPU = 0x120; public const int MAX_PSTATES_PER_GPU = 8; public const int MAX_USAGES_PER_GPU = 33; @@ -242,23 +256,25 @@ Marshal.SizeOf(typeof(NvUsages)) | 0x10000; public static readonly uint GPU_COOLER_SETTINGS_VER = (uint) Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000; - public static readonly uint GPU_MEMORY_INFO_VER = (uint) + public static readonly uint GPU_MEMORY_INFO_VER = (uint) Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000; public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint) Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000; - + public static readonly uint GPU_COOLER_LEVELS_VER = (uint) + Marshal.SizeOf(typeof(NvGPUCoolerLevels)) | 0x10000; + private delegate IntPtr nvapi_QueryInterfaceDelegate(uint id); private delegate NvStatus NvAPI_InitializeDelegate(); private delegate NvStatus NvAPI_GPU_GetFullNameDelegate( NvPhysicalGpuHandle gpuHandle, StringBuilder name); public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate( - NvPhysicalGpuHandle gpuHandle, int sensorIndex, + NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvGPUThermalSettings nvGPUThermalSettings); public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate( - NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, + NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate( [Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); @@ -273,6 +289,9 @@ public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate( NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvGPUCoolerSettings nvGPUCoolerSettings); + public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate( + NvPhysicalGpuHandle gpuHandle, int coolerIndex, + ref NvGPUCoolerLevels NvGPUCoolerLevels); public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate( NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate( @@ -284,12 +303,12 @@ private static readonly bool available; private static readonly nvapi_QueryInterfaceDelegate nvapi_QueryInterface; private static readonly NvAPI_InitializeDelegate NvAPI_Initialize; - private static readonly NvAPI_GPU_GetFullNameDelegate + private static readonly NvAPI_GPU_GetFullNameDelegate _NvAPI_GPU_GetFullName; private static readonly NvAPI_GetInterfaceVersionStringDelegate _NvAPI_GetInterfaceVersionString; - public static readonly NvAPI_GPU_GetThermalSettingsDelegate + public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate NvAPI_EnumNvidiaDisplayHandle; @@ -307,6 +326,8 @@ NvAPI_GPU_GetUsages; public static readonly NvAPI_GPU_GetCoolerSettingsDelegate NvAPI_GPU_GetCoolerSettings; + public static readonly NvAPI_GPU_SetCoolerLevelsDelegate + NvAPI_GPU_SetCoolerLevels; public static readonly NvAPI_GPU_GetMemoryInfoDelegate NvAPI_GPU_GetMemoryInfo; public static readonly NvAPI_GetDisplayDriverVersionDelegate @@ -345,9 +366,8 @@ } } - private static void GetDelegate(uint id, out T newDelegate) - where T : class - { + private static void GetDelegate(uint id, out T newDelegate) + where T : class { IntPtr ptr = nvapi_QueryInterface(id); if (ptr != IntPtr.Zero) { newDelegate = @@ -357,7 +377,7 @@ } } - static NVAPI() { + static NVAPI() { DllImportAttribute attribute = new DllImportAttribute(GetDllName()); attribute.CallingConvention = CallingConvention.Cdecl; attribute.PreserveSig = true; @@ -382,6 +402,7 @@ 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); diff -r d882720734bf -r 65a1ae21325d Hardware/Nvidia/NvidiaGPU.cs --- a/Hardware/Nvidia/NvidiaGPU.cs Thu Jul 07 20:41:09 2011 +0000 +++ b/Hardware/Nvidia/NvidiaGPU.cs Thu Jul 07 21:53:09 2011 +0000 @@ -20,6 +20,7 @@ the Initial Developer. All Rights Reserved. Contributor(s): + Christian Vallières Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or @@ -52,12 +53,15 @@ private readonly Sensor[] loads; private readonly Sensor control; private readonly Sensor memoryLoad; + private readonly Control fanControl; - public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle, - NvDisplayHandle? displayHandle, ISettings settings) - : base(GetName(handle), new Identifier("nvidiagpu", - adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) - { + private bool restoreDefaultFanSpeedRequired; + private NvLevel initialFanSpeedValue; + + public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle, + NvDisplayHandle? displayHandle, ISettings settings) + : base(GetName(handle), new Identifier("nvidiagpu", + adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) { this.adapterIndex = adapterIndex; this.handle = handle; this.displayHandle = displayHandle; @@ -103,6 +107,18 @@ memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings); control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); + + NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); + if (coolerSettings.Count > 0) { + fanControl = new Control(control, settings, + coolerSettings.Cooler[0].DefaultMin, + coolerSettings.Cooler[0].DefaultMax); + fanControl.ControlModeChanged += ControlModeChanged; + fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged; + ControlModeChanged(fanControl); + control.Control = fanControl; + } + Update(); } private static string GetName(NvPhysicalGpuHandle handle) { @@ -123,12 +139,26 @@ settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER; settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU; settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU]; - if (NVAPI.NvAPI_GPU_GetThermalSettings != null && + if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null && NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL, - ref settings) != NvStatus.OK) { - settings.Count = 0; + ref settings) == NvStatus.OK)) + { + settings.Count = 0; + } + return settings; + } + + private NvGPUCoolerSettings GetCoolerSettings() { + NvGPUCoolerSettings settings = new NvGPUCoolerSettings(); + settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER; + settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU]; + if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null && + NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, + ref settings) == NvStatus.OK)) + { + settings.Count = 0; } - return settings; + return settings; } private uint[] GetClocks() { @@ -144,7 +174,7 @@ public override void Update() { NvGPUThermalSettings settings = GetThermalSettings(); - foreach (Sensor sensor in temperatures) + foreach (Sensor sensor in temperatures) sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; if (fan != null) { @@ -167,7 +197,7 @@ NvPStates states = new NvPStates(); states.Version = NVAPI.GPU_PSTATES_VER; states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU]; - if (NVAPI.NvAPI_GPU_GetPStates != null && + if (NVAPI.NvAPI_GPU_GetPStates != null && NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) { for (int i = 0; i < 3; i++) if (states.PStates[i].Present) { @@ -188,12 +218,9 @@ } } - NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings(); - coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER; - coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU]; - if (NVAPI.NvAPI_GPU_GetCoolerSettings != null && - NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) == - NvStatus.OK && coolerSettings.Count > 0) { + + NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); + if (coolerSettings.Count > 0) { control.Value = coolerSettings.Cooler[0].CurrentLevel; ActivateSensor(control); } @@ -202,9 +229,8 @@ memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER; memoryInfo.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) == - NvStatus.OK) - { + NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) == + NvStatus.OK) { uint totalMemory = memoryInfo.Values[0]; uint freeMemory = memoryInfo.Values[4]; float usedMemory = Math.Max(totalMemory - freeMemory, 0); @@ -221,9 +247,8 @@ r.AppendFormat("Name: {0}{1}", name, Environment.NewLine); r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine); - - if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) - { + + if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) { NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion(); driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER; if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value, @@ -231,7 +256,7 @@ r.Append("Driver Version: "); r.Append(driverVersion.DriverVersion / 100); r.Append("."); - r.Append((driverVersion.DriverVersion % 100).ToString("00", + r.Append((driverVersion.DriverVersion % 100).ToString("00", CultureInfo.InvariantCulture)); r.AppendLine(); r.Append("Driver Branch: "); @@ -269,7 +294,7 @@ r.AppendLine(status.ToString()); } r.AppendLine(); - } + } if (NVAPI.NvAPI_GPU_GetAllClocks != null) { NvClocks allClocks = new NvClocks(); @@ -290,10 +315,10 @@ r.AppendLine(status.ToString()); } r.AppendLine(); - } - + } + if (NVAPI.NvAPI_GPU_GetTachReading != null) { - int tachValue; + int tachValue; NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue); r.AppendLine("Tachometer"); @@ -332,7 +357,7 @@ usages.Version = NVAPI.GPU_USAGES_VER; usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU]; NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages); - + r.AppendLine("Usages"); r.AppendLine(); if (status == NvStatus.OK) { @@ -394,7 +419,7 @@ NvMemoryInfo memoryInfo = new NvMemoryInfo(); memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER; memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU]; - NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, + NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo); r.AppendLine("Memory Info"); @@ -412,5 +437,45 @@ return r.ToString(); } + + private void SoftwareControlValueChanged(IControl control) { + SaveDefaultFanSpeed(); + NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels(); + coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER; + coolerLevels.Levels = new 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); + } + + private void SaveDefaultFanSpeed() { + if (!restoreDefaultFanSpeedRequired) { + NvGPUCoolerSettings coolerSettings = GetCoolerSettings(); + if (coolerSettings.Count > 0) { + restoreDefaultFanSpeedRequired = true; + initialFanSpeedValue.Level = coolerSettings.Cooler[0].CurrentLevel; + initialFanSpeedValue.Policy = coolerSettings.Cooler[0].CurrentPolicy; + } + } + } + + private void ControlModeChanged(IControl control) { + if (control.ControlMode == ControlMode.Default) { + RestoreDefaultFanSpeed(); + } else { + SoftwareControlValueChanged(control); + } + } + + private void RestoreDefaultFanSpeed() { + if (restoreDefaultFanSpeedRequired) { + NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels(); + coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER; + coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU]; + coolerLevels.Levels[0] = initialFanSpeedValue; + NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels); + restoreDefaultFanSpeedRequired = false; + } + } } }