moel@1: /*
moel@1:   
moel@1:   Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1: 
moel@1:   The contents of this file are subject to the Mozilla Public License Version
moel@1:   1.1 (the "License"); you may not use this file except in compliance with
moel@1:   the License. You may obtain a copy of the License at
moel@1:  
moel@1:   http://www.mozilla.org/MPL/
moel@1: 
moel@1:   Software distributed under the License is distributed on an "AS IS" basis,
moel@1:   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1:   for the specific language governing rights and limitations under the License.
moel@1: 
moel@1:   The Original Code is the Open Hardware Monitor code.
moel@1: 
moel@1:   The Initial Developer of the Original Code is 
moel@1:   Michael Möller <m.moeller@gmx.ch>.
moel@1:   Portions created by the Initial Developer are Copyright (C) 2009-2010
moel@1:   the Initial Developer. All Rights Reserved.
moel@1: 
moel@1:   Contributor(s):
moel@1: 
moel@1:   Alternatively, the contents of this file may be used under the terms of
moel@1:   either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1:   the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1:   in which case the provisions of the GPL or the LGPL are applicable instead
moel@1:   of those above. If you wish to allow use of your version of this file only
moel@1:   under the terms of either the GPL or the LGPL, and not to allow others to
moel@1:   use your version of this file under the terms of the MPL, indicate your
moel@1:   decision by deleting the provisions above and replace them with the notice
moel@1:   and other provisions required by the GPL or the LGPL. If you do not delete
moel@1:   the provisions above, a recipient may use your version of this file under
moel@1:   the terms of any one of the MPL, the GPL or the LGPL.
moel@1:  
moel@1: */
moel@1: 
moel@1: using System;
moel@1: using System.Runtime.InteropServices;
moel@1: using System.Text;
moel@1: 
moel@1: namespace OpenHardwareMonitor.Hardware.Nvidia {
moel@1: 
moel@165:   internal enum NvStatus {
moel@1:     OK = 0,
moel@1:     ERROR = -1,
moel@1:     LIBRARY_NOT_FOUND = -2,
moel@1:     NO_IMPLEMENTATION = -3,
moel@1:     API_NOT_INTIALIZED = -4,
moel@1:     INVALID_ARGUMENT = -5,
moel@1:     NVIDIA_DEVICE_NOT_FOUND = -6,
moel@1:     END_ENUMERATION = -7,
moel@1:     INVALID_HANDLE = -8,
moel@1:     INCOMPATIBLE_STRUCT_VERSION = -9,
moel@1:     HANDLE_INVALIDATED = -10,
moel@1:     OPENGL_CONTEXT_NOT_CURRENT = -11,
moel@1:     NO_GL_EXPERT = -12,
moel@1:     INSTRUMENTATION_DISABLED = -13,
moel@1:     EXPECTED_LOGICAL_GPU_HANDLE = -100,
moel@1:     EXPECTED_PHYSICAL_GPU_HANDLE = -101,
moel@1:     EXPECTED_DISPLAY_HANDLE = -102,
moel@1:     INVALID_COMBINATION = -103,
moel@1:     NOT_SUPPORTED = -104,
moel@1:     PORTID_NOT_FOUND = -105,
moel@1:     EXPECTED_UNATTACHED_DISPLAY_HANDLE = -106,
moel@1:     INVALID_PERF_LEVEL = -107,
moel@1:     DEVICE_BUSY = -108,
moel@1:     NV_PERSIST_FILE_NOT_FOUND = -109,
moel@1:     PERSIST_DATA_NOT_FOUND = -110,
moel@1:     EXPECTED_TV_DISPLAY = -111,
moel@1:     EXPECTED_TV_DISPLAY_ON_DCONNECTOR = -112,
moel@1:     NO_ACTIVE_SLI_TOPOLOGY = -113,
moel@1:     SLI_RENDERING_MODE_NOTALLOWED = -114,
moel@1:     EXPECTED_DIGITAL_FLAT_PANEL = -115,
moel@1:     ARGUMENT_EXCEED_MAX_SIZE = -116,
moel@1:     DEVICE_SWITCHING_NOT_ALLOWED = -117,
moel@1:     TESTING_CLOCKS_NOT_SUPPORTED = -118,
moel@1:     UNKNOWN_UNDERSCAN_CONFIG = -119,
moel@1:     TIMEOUT_RECONFIGURING_GPU_TOPO = -120,
moel@1:     DATA_NOT_FOUND = -121,
moel@1:     EXPECTED_ANALOG_DISPLAY = -122,
moel@1:     NO_VIDLINK = -123,
moel@1:     REQUIRES_REBOOT = -124,
moel@1:     INVALID_HYBRID_MODE = -125,
moel@1:     MIXED_TARGET_TYPES = -126,
moel@1:     SYSWOW64_NOT_SUPPORTED = -127,
moel@1:     IMPLICIT_SET_GPU_TOPOLOGY_CHANGE_NOT_ALLOWED = -128,
moel@1:     REQUEST_USER_TO_CLOSE_NON_MIGRATABLE_APPS = -129,
moel@1:     OUT_OF_MEMORY = -130,
moel@1:     WAS_STILL_DRAWING = -131,
moel@1:     FILE_NOT_FOUND = -132,
moel@1:     TOO_MANY_UNIQUE_STATE_OBJECTS = -133,
moel@1:     INVALID_CALL = -134,
moel@1:     D3D10_1_LIBRARY_NOT_FOUND = -135,
moel@1:     FUNCTION_NOT_FOUND = -136
moel@165:   }
moel@1: 
moel@165:   internal enum NvThermalController {
moel@1:     NONE = 0,
moel@1:     GPU_INTERNAL,  
moel@1:     ADM1032,
moel@1:     MAX6649,       
moel@1:     MAX1617,      
moel@1:     LM99,      
moel@1:     LM89,         
moel@1:     LM64,         
moel@1:     ADT7473,
moel@1:     SBMAX6649,
moel@1:     VBIOSEVT,  
moel@1:     OS,    
moel@1:     UNKNOWN = -1,
moel@165:   }
moel@1: 
moel@165:   internal enum NvThermalTarget {
moel@1:     NONE = 0,
moel@1:     GPU = 1,
moel@1:     MEMORY = 2,
moel@1:     POWER_SUPPLY = 4,
moel@1:     BOARD = 8,
moel@1:     ALL = 15,
moel@1:     UNKNOWN = -1
moel@1:   };
moel@1: 
moel@61:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvSensor {
moel@1:     public NvThermalController Controller;
moel@140:     public uint DefaultMinTemp;
moel@140:     public uint DefaultMaxTemp;
moel@140:     public uint CurrentTemp;
moel@1:     public NvThermalTarget Target;     
moel@1:   }
moel@1: 
moel@61:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvGPUThermalSettings {
moel@140:     public uint Version;
moel@140:     public uint Count;
moel@1:     [MarshalAs(UnmanagedType.ByValArray, 
moel@1:       SizeConst = NVAPI.MAX_THERMAL_SENSORS_PER_GPU)]
moel@1:     public NvSensor[] Sensor;
moel@1:   }
moel@1: 
moel@61:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct NvDisplayHandle {
moel@195:     private readonly IntPtr ptr;
moel@1:   }
moel@1: 
moel@61:   [StructLayout(LayoutKind.Sequential)]
moel@165:   internal struct NvPhysicalGpuHandle {
moel@195:     private readonly IntPtr ptr;
moel@1:   }
moel@1: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvClocks {
moel@140:     public uint Version;
moel@140:     [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_CLOCKS_PER_GPU)]
moel@140:     public uint[] Clock;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvPState {
moel@140:     public bool Present;
moel@140:     public int Percentage;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvPStates {
moel@140:     public uint Version;
moel@140:     public uint Flags;
moel@140:     [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_PSTATES_PER_GPU)]
moel@140:     public NvPState[] PStates;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvUsages {
moel@140:     public uint Version;
moel@140:     [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_USAGES_PER_GPU)]
moel@140:     public uint[] Usage;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvCooler {
moel@140:     public int Type;
moel@140:     public int Controller;
moel@140:     public int DefaultMin;
moel@140:     public int DefaultMax;
moel@140:     public int CurrentMin;
moel@140:     public int CurrentMax;
moel@140:     public int CurrentLevel;
moel@140:     public int DefaultPolicy;
moel@140:     public int CurrentPolicy;
moel@140:     public int Target;
moel@140:     public int ControlType;
moel@140:     public int Active;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvGPUCoolerSettings {
moel@140:     public uint Version;
moel@140:     public uint Count;
moel@140:     [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_COOLER_PER_GPU)]
moel@140:     public NvCooler[] Cooler;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvMemoryInfo {
moel@140:     public uint Version;
moel@140:     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 
moel@140:       NVAPI.MAX_MEMORY_VALUES_PER_GPU)]
moel@140:     public uint[] Values;
moel@140:   }
moel@140: 
moel@140:   [StructLayout(LayoutKind.Sequential, Pack = 8)]
moel@165:   internal struct NvDisplayDriverVersion {
moel@140:     public uint Version;
moel@140:     public uint DriverVersion;
moel@140:     public uint BldChangeListNum;
moel@140:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NVAPI.SHORT_STRING_MAX)]
moel@140:     public string BuildBranch;
moel@140:     [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NVAPI.SHORT_STRING_MAX)]
moel@140:     public string Adapter;
moel@165:   }
moel@140: 
moel@165:   internal class NVAPI {
moel@1: 
moel@1:     public const int MAX_PHYSICAL_GPUS = 64;
moel@140:     public const int SHORT_STRING_MAX = 64;
moel@140: 
moel@140:     public const int MAX_THERMAL_SENSORS_PER_GPU = 3;    
moel@140:     public const int MAX_CLOCKS_PER_GPU = 0x120;
moel@140:     public const int MAX_PSTATES_PER_GPU = 8;
moel@140:     public const int MAX_USAGES_PER_GPU = 33;
moel@140:     public const int MAX_COOLER_PER_GPU = 20;
moel@140:     public const int MAX_MEMORY_VALUES_PER_GPU = 5;
moel@140: 
moel@140:     public static readonly uint GPU_THERMAL_SETTINGS_VER = (uint)
moel@1:       Marshal.SizeOf(typeof(NvGPUThermalSettings)) | 0x10000;
moel@140:     public static readonly uint GPU_CLOCKS_VER = (uint)
moel@140:       Marshal.SizeOf(typeof(NvClocks)) | 0x20000;
moel@140:     public static readonly uint GPU_PSTATES_VER = (uint)
moel@140:       Marshal.SizeOf(typeof(NvPStates)) | 0x10000;
moel@140:     public static readonly uint GPU_USAGES_VER = (uint)
moel@140:       Marshal.SizeOf(typeof(NvUsages)) | 0x10000;
moel@140:     public static readonly uint GPU_COOLER_SETTINGS_VER = (uint)
moel@140:       Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000;
moel@140:     public static readonly uint GPU_MEMORY_INFO_VER = (uint) 
moel@140:       Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000;
moel@140:     public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint)
moel@140:       Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000;
moel@140:       
moel@1:     private delegate IntPtr nvapi_QueryInterfaceDelegate(uint id);
moel@1:     private delegate NvStatus NvAPI_InitializeDelegate();
moel@1:     private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(
moel@1:       NvPhysicalGpuHandle gpuHandle, StringBuilder name);
moel@1: 
moel@1:     public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(
moel@1:       NvPhysicalGpuHandle gpuHandle, int sensorIndex, 
moel@1:       ref NvGPUThermalSettings nvGPUThermalSettings);
moel@1:     public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum,
moel@1:       ref NvDisplayHandle displayHandle);
moel@1:     public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(
moel@1:       NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, 
moel@140:       out uint gpuCount);
moel@1:     public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate(
moel@1:       [Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
moel@38:     public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(
moel@38:       NvPhysicalGpuHandle gpuHandle, out int value);
moel@140:     public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(
moel@140:       NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks);
moel@140:     public delegate NvStatus NvAPI_GPU_GetPStatesDelegate(
moel@140:       NvPhysicalGpuHandle gpuHandle, ref NvPStates nvPStates);
moel@140:     public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(
moel@140:       NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages);
moel@140:     public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(
moel@140:       NvPhysicalGpuHandle gpuHandle, int coolerIndex,
moel@140:       ref NvGPUCoolerSettings nvGPUCoolerSettings);
moel@140:     public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(
moel@140:       NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo);
moel@140:     public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(
moel@140:       NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion
moel@140:       nvDisplayDriverVersion);
moel@140:     public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(
moel@140:       StringBuilder version);
moel@1: 
moel@195:     private static readonly bool available;
moel@195:     private static readonly nvapi_QueryInterfaceDelegate nvapi_QueryInterface;
moel@195:     private static readonly NvAPI_InitializeDelegate NvAPI_Initialize;
moel@195:     private static readonly NvAPI_GPU_GetFullNameDelegate 
moel@195:       _NvAPI_GPU_GetFullName;
moel@195:     private static readonly NvAPI_GetInterfaceVersionStringDelegate
moel@140:       _NvAPI_GetInterfaceVersionString;
moel@1: 
moel@140:     public static readonly NvAPI_GPU_GetThermalSettingsDelegate 
moel@1:       NvAPI_GPU_GetThermalSettings;
moel@140:     public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate
moel@1:       NvAPI_EnumNvidiaDisplayHandle;
moel@140:     public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate
moel@1:       NvAPI_GetPhysicalGPUsFromDisplay;
moel@140:     public static readonly NvAPI_EnumPhysicalGPUsDelegate
moel@1:       NvAPI_EnumPhysicalGPUs;
moel@140:     public static readonly NvAPI_GPU_GetTachReadingDelegate
moel@38:       NvAPI_GPU_GetTachReading;
moel@140:     public static readonly NvAPI_GPU_GetAllClocksDelegate
moel@140:       NvAPI_GPU_GetAllClocks;
moel@140:     public static readonly NvAPI_GPU_GetPStatesDelegate
moel@140:       NvAPI_GPU_GetPStates;
moel@140:     public static readonly NvAPI_GPU_GetUsagesDelegate
moel@140:       NvAPI_GPU_GetUsages;
moel@140:     public static readonly NvAPI_GPU_GetCoolerSettingsDelegate
moel@140:       NvAPI_GPU_GetCoolerSettings;
moel@140:     public static readonly NvAPI_GPU_GetMemoryInfoDelegate
moel@140:       NvAPI_GPU_GetMemoryInfo;
moel@140:     public static readonly NvAPI_GetDisplayDriverVersionDelegate
moel@167:       NvAPI_GetDisplayDriverVersion;
moel@167: 
moel@167:     private NVAPI() { }
moel@1: 
moel@1:     public static NvStatus NvAPI_GPU_GetFullName(NvPhysicalGpuHandle gpuHandle,
moel@1:       out string name) {
moel@1:       StringBuilder builder = new StringBuilder(SHORT_STRING_MAX);
moel@101:       NvStatus status;
moel@101:       if (_NvAPI_GPU_GetFullName != null)
moel@101:         status = _NvAPI_GPU_GetFullName(gpuHandle, builder);
moel@101:       else
moel@101:         status = NvStatus.FUNCTION_NOT_FOUND;
moel@1:       name = builder.ToString();
moel@1:       return status;
moel@1:     }
moel@1: 
moel@140:     public static NvStatus NvAPI_GetInterfaceVersionString(out string version) {
moel@140:       StringBuilder builder = new StringBuilder(SHORT_STRING_MAX);
moel@140:       NvStatus status;
moel@140:       if (_NvAPI_GetInterfaceVersionString != null)
moel@140:         status = _NvAPI_GetInterfaceVersionString(builder);
moel@140:       else
moel@140:         status = NvStatus.FUNCTION_NOT_FOUND;
moel@140:       version = builder.ToString();
moel@140:       return status;
moel@140:     }
moel@140: 
moel@1:     private static string GetDllName() {
moel@1:       if (IntPtr.Size == 4) {
moel@1:         return "nvapi.dll";
moel@1:       } else {
moel@1:         return "nvapi64.dll";
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     private static void GetDelegate<T>(uint id, out T newDelegate) 
moel@1:       where T : class 
moel@1:     {
moel@1:       IntPtr ptr = nvapi_QueryInterface(id);
moel@38:       if (ptr != IntPtr.Zero) {
moel@38:         newDelegate =
moel@38:           Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T;
moel@38:       } else {
moel@38:         newDelegate = null;
moel@38:       }
moel@1:     }
moel@1: 
moel@1:     static NVAPI() { 
moel@1:       DllImportAttribute attribute = new DllImportAttribute(GetDllName());
moel@1:       attribute.CallingConvention = CallingConvention.Cdecl;
moel@1:       attribute.PreserveSig = true;
moel@1:       attribute.EntryPoint = "nvapi_QueryInterface";
moel@1:       PInvokeDelegateFactory.CreateDelegate(attribute,
moel@1:         out nvapi_QueryInterface);
moel@1: 
moel@1:       try {
moel@1:         GetDelegate(0x0150E828, out NvAPI_Initialize);
moel@1:       } catch (DllNotFoundException) { return; } 
moel@121:         catch (EntryPointNotFoundException) { return; } 
moel@1:         catch (ArgumentNullException) { return; }
moel@1: 
moel@1:       if (NvAPI_Initialize() == NvStatus.OK) {
moel@1:         GetDelegate(0xE3640A56, out NvAPI_GPU_GetThermalSettings);
moel@1:         GetDelegate(0xCEEE8E9F, out _NvAPI_GPU_GetFullName);
moel@1:         GetDelegate(0x9ABDD40D, out NvAPI_EnumNvidiaDisplayHandle);
moel@1:         GetDelegate(0x34EF9506, out NvAPI_GetPhysicalGPUsFromDisplay);
moel@1:         GetDelegate(0xE5AC921F, out NvAPI_EnumPhysicalGPUs);
moel@140:         GetDelegate(0x5F608315, out NvAPI_GPU_GetTachReading);
moel@140:         GetDelegate(0x1BD69F49, out NvAPI_GPU_GetAllClocks);
moel@140:         GetDelegate(0x60DED2ED, out NvAPI_GPU_GetPStates);
moel@140:         GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);
moel@140:         GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings);
moel@140:         GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo);
moel@140:         GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion);
moel@140:         GetDelegate(0x01053FA5, out _NvAPI_GetInterfaceVersionString);
moel@140: 
moel@1:         available = true;
moel@1:       }
moel@1:     }
moel@1: 
moel@1:     public static bool IsAvailable {
moel@1:       get { return available; }
moel@1:     }
moel@1: 
moel@1:   }
moel@1: }