From 5dc6cb95c8b3785cfc9b956f673e24c387ab8009 Mon Sep 17 00:00:00 2001 From: kolos Date: Tue, 1 Jun 2021 13:30:52 +0200 Subject: [PATCH] Add D3D GPU Sensors (#426) Thanks to @kolos. --- .../Hardware/D3DDisplayDevice.cs | 238 +++++++ .../Hardware/Gpu/AmdGpu.cs | 123 +++- .../Hardware/Gpu/AmdGpuGroup.cs | 7 +- .../Hardware/Gpu/NvidiaGpu.cs | 196 +++++- .../Hardware/Gpu/NvidiaGroup.cs | 6 +- LibreHardwareMonitorLib/Interop/CfgMgr32.cs | 28 + LibreHardwareMonitorLib/Interop/D3dkmdt.cs | 48 ++ LibreHardwareMonitorLib/Interop/D3dkmth.cs | 563 +++++++++++++++++ LibreHardwareMonitorLib/Interop/Gdi32.cs | 29 + LibreHardwareMonitorLib/Interop/NvidiaML.cs | 592 ++++++++++-------- LibreHardwareMonitorLib/Interop/WinNt.cs | 37 ++ 11 files changed, 1520 insertions(+), 347 deletions(-) create mode 100644 LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs create mode 100644 LibreHardwareMonitorLib/Interop/CfgMgr32.cs create mode 100644 LibreHardwareMonitorLib/Interop/D3dkmdt.cs create mode 100644 LibreHardwareMonitorLib/Interop/D3dkmth.cs create mode 100644 LibreHardwareMonitorLib/Interop/Gdi32.cs create mode 100644 LibreHardwareMonitorLib/Interop/WinNt.cs diff --git a/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs new file mode 100644 index 0000000..fda43de --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs @@ -0,0 +1,238 @@ +// 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. +// Ported from: https://github.com/processhacker/processhacker/blob/master/plugins/ExtendedTools/gpumon.c + +using System; +using System.Linq; +using System.Runtime.InteropServices; +using LibreHardwareMonitor.Interop; + +namespace LibreHardwareMonitor.Hardware +{ + internal static class D3DDisplayDevice + { + public static string[] GetDeviceIdentifiers() + { + if (CfgMgr32.CM_Get_Device_Interface_List_Size(out uint size, ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CfgMgr32.CR_SUCCESS) + return null; + + + char[] data = new char[size]; + if (CfgMgr32.CM_Get_Device_Interface_List(ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, data, (uint)data.Length, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CfgMgr32.CR_SUCCESS) + return new string(data).Split('\0').Where(m => !string.IsNullOrEmpty(m)).ToArray(); + + + return null; + } + + public static bool GetDeviceInfoByIdentifier(string deviceIdentifier, out D3DDeviceInfo deviceInfo) + { + deviceInfo = new D3DDeviceInfo(); + + OpenAdapterFromDeviceName(out uint status, deviceIdentifier, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter); + if (status != WinNt.STATUS_SUCCESS) + return false; + + + GetAdapterType(out status, adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterType); + if (status != WinNt.STATUS_SUCCESS) + return false; + + if (!adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.SoftwareDevice)) + return false; + + + GetQueryStatisticsAdapterInformation(out status, adapter, out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; + + + uint segmentCount = adapterInformation.NbSegments; + uint nodeCount = adapterInformation.NodeCount; + + deviceInfo.Nodes = new D3DDeviceNodeInfo[nodeCount]; + + for (uint nodeId = 0; nodeId < nodeCount; nodeId++) + { + GetNodeMetaData(out status, adapter, nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaData); + if (status != WinNt.STATUS_SUCCESS) + return false; + + + GetQueryStatisticsNode(out status, adapter, nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; + + + deviceInfo.Nodes[nodeId] = new D3DDeviceNodeInfo + { + Id = nodeId, Name = GetNodeEngineTypeString(nodeMetaData), RunningTime = nodeInformation.GlobalInformation.RunningTime.QuadPart, QueryTime = DateTime.Now + }; + } + + for (uint segmentId = 0; segmentId < segmentCount; segmentId++) + { + GetQueryStatisticsSegment(out status, adapter, segmentId, out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; + + + ulong commitLimit = segmentInformation.CommitLimit; + ulong bytesResident = segmentInformation.BytesResident; + ulong bytesCommitted = segmentInformation.BytesCommitted; + + uint aperture = segmentInformation.Aperture; + + if (aperture == 1) + { + deviceInfo.GpuSharedLimit += commitLimit; + deviceInfo.GpuSharedUsed += bytesResident; + deviceInfo.GpuSharedMax += bytesCommitted; + } + else + { + deviceInfo.GpuDedicatedLimit += commitLimit; + deviceInfo.GpuDedicatedUsed += bytesResident; + deviceInfo.GpuDedicatedMax += bytesCommitted; + } + } + + CloseAdapter(out status, adapter); + return status == WinNt.STATUS_SUCCESS; + } + + private static string GetNodeEngineTypeString(D3dkmth.D3DKMT_NODEMETADATA nodeMetaData) + { + return nodeMetaData.NodeData.EngineType switch + { + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OTHER => "D3D " + nodeMetaData.NodeData.FriendlyName, + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_3D => "D3D 3D", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_DECODE => "D3D Video Decode", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_ENCODE => "D3D Video Encode", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_PROCESSING => "D3D Video Processing", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_SCENE_ASSEMBLY => "D3D Scene Assembly", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_COPY => "D3D Copy", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OVERLAY => "D3D Overlay", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_CRYPTO => "D3D Crypto", + _ => "D3D Unknown", + }; + } + + private static void GetNodeMetaData(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaDataResult) + { + IntPtr nodeMetaDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA))); + nodeMetaDataResult = new D3dkmth.D3DKMT_NODEMETADATA { NodeOrdinalAndAdapterIndex = nodeId }; + Marshal.StructureToPtr(nodeMetaDataResult, nodeMetaDataPtr, true); + + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO + { + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_NODEMETADATA, + pPrivateDriverData = nodeMetaDataPtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA)) + }; + + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + nodeMetaDataResult = Marshal.PtrToStructure(nodeMetaDataPtr); + Marshal.FreeHGlobal(nodeMetaDataPtr); + } + + private static void GetQueryStatisticsNode(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation) + { + var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QueryNode = { NodeId = nodeId } }; + + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS + { + AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_NODE, QueryElement = queryElement + }; + + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + + nodeInformation = queryStatistics.QueryResult.NodeInformation; + } + + private static void GetQueryStatisticsSegment + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + uint segmentId, + out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation) + { + var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QuerySegment = { SegmentId = segmentId } }; + + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS + { + AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_SEGMENT, QueryElement = queryElement + }; + + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + + segmentInformation = queryStatistics.QueryResult.SegmentInformation; + } + + private static void GetQueryStatisticsAdapterInformation + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation) + { + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS { AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_ADAPTER, }; + + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + + adapterInformation = queryStatistics.QueryResult.AdapterInformation; + } + + private static void GetAdapterType(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterTypeResult) + { + IntPtr adapterTypePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE))); + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO + { + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_ADAPTERTYPE, + pPrivateDriverData = adapterTypePtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE)) + }; + + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + adapterTypeResult = Marshal.PtrToStructure(adapterTypePtr); + Marshal.FreeHGlobal(adapterTypePtr); + } + + private static void OpenAdapterFromDeviceName(out uint status, string displayDeviceName, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) + { + adapter = new D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME { pDeviceName = displayDeviceName }; + status = Gdi32.D3DKMTOpenAdapterFromDeviceName(ref adapter); + } + + private static void CloseAdapter(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) + { + var closeAdapter = new D3dkmth.D3DKMT_CLOSEADAPTER { hAdapter = adapter.hAdapter }; + status = Gdi32.D3DKMTCloseAdapter(ref closeAdapter); + } + + public struct D3DDeviceNodeInfo + { + public ulong Id; + public string Name; + public long RunningTime; + public DateTime QueryTime; + } + + public struct D3DDeviceInfo + { + public ulong GpuSharedLimit; + public ulong GpuDedicatedLimit; + + public ulong GpuSharedUsed; + public ulong GpuDedicatedUsed; + + public ulong GpuSharedMax; + public ulong GpuDedicatedMax; + + public D3DDeviceNodeInfo[] Nodes; + } + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs index 09b7e5b..2600f30 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs @@ -16,19 +16,26 @@ namespace LibreHardwareMonitor.Hardware.Gpu private readonly int _adapterIndex; private readonly IntPtr _context = IntPtr.Zero; - private readonly bool _framemetricsStarted = false; - private readonly Sensor _controlSensor; private readonly Sensor _coreClock; private readonly Sensor _coreLoad; private readonly Sensor _coreVoltage; - private readonly bool _overdriveApiSupported; private readonly int _currentOverdriveApiLevel; private readonly Sensor _fan; private readonly Control _fanControl; + private readonly bool _frameMetricsStarted; + private readonly Sensor _fullscreenFps; + private readonly Sensor _gpuDedicatedMemoryUsage; + private readonly Sensor[] _gpuNodeUsage; + private readonly DateTime[] _gpuNodeUsagePrevTick; + private readonly long[] _gpuNodeUsagePrevValue; + private readonly Sensor _gpuSharedMemoryUsage; private readonly Sensor _memoryClock; private readonly Sensor _memoryLoad; + private readonly int _memorySensorIndex; private readonly Sensor _memoryVoltage; + private readonly int _nodeSensorIndex; + private readonly bool _overdriveApiSupported; private readonly Sensor _powerCore; private readonly Sensor _powerPpt; private readonly Sensor _powerSoC; @@ -43,14 +50,14 @@ namespace LibreHardwareMonitor.Hardware.Gpu private readonly Sensor _temperaturePlx; private readonly Sensor _temperatureSoC; private readonly Sensor _temperatureVddc; - private readonly Sensor _fullscreenFPS; + private readonly string _windowsDeviceName; - public AmdGpu(string name, int adapterIndex, int busNumber, int deviceNumber, ISettings settings) - : base(name, new Identifier("gpu-amd", adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) + public AmdGpu(AtiAdlxx.ADLAdapterInfo adapterInfo, ISettings settings) + : base(adapterInfo.AdapterName.Trim(), new Identifier("gpu-amd", adapterInfo.AdapterIndex.ToString(CultureInfo.InvariantCulture)), settings) { - _adapterIndex = adapterIndex; - BusNumber = busNumber; - DeviceNumber = deviceNumber; + _adapterIndex = adapterInfo.AdapterIndex; + BusNumber = adapterInfo.BusNumber; + DeviceNumber = adapterInfo.DeviceNumber; _temperatureCore = new Sensor("GPU Core", 0, SensorType.Temperature, this, settings); _temperatureMemory = new Sensor("GPU Memory", 1, SensorType.Temperature, this, settings); @@ -81,7 +88,40 @@ namespace LibreHardwareMonitor.Hardware.Gpu _powerSoC = new Sensor("GPU SoC", 2, SensorType.Power, this, settings); _powerTotal = new Sensor("GPU Package", 3, SensorType.Power, this, settings); - _fullscreenFPS = new Sensor("Fullscreen FPS", 0, SensorType.Factor, this, settings); + _fullscreenFps = new Sensor("Fullscreen FPS", 0, SensorType.Factor, this, settings); + + if (!Software.OperatingSystem.IsUnix) + { + string convertedPnpString = adapterInfo.PNPString.Replace("\\", "#"); + string[] deviceIdentifiers = D3DDisplayDevice.GetDeviceIdentifiers(); + if (deviceIdentifiers != null) + { + foreach (string deviceIdentifier in deviceIdentifiers) + { + if (deviceIdentifier.IndexOf(convertedPnpString, StringComparison.OrdinalIgnoreCase) != -1 && + D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceIdentifier, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _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); + + _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + _gpuNodeUsage[node.Id] = new Sensor(node.Name, _nodeSensorIndex++, SensorType.Load, this, settings); + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + } + + break; + } + } + } + } int supported = 0; int enabled = 0; @@ -91,9 +131,9 @@ namespace LibreHardwareMonitor.Hardware.Gpu { if (supported == AtiAdlxx.ADL_TRUE && AtiAdlxx.ADL2_Adapter_FrameMetrics_Start(_context, _adapterIndex, 0) == AtiAdlxx.ADLStatus.ADL_OK) { - _framemetricsStarted = true; - _fullscreenFPS.Value = -1; - ActivateSensor(_fullscreenFPS); + _frameMetricsStarted = true; + _fullscreenFps.Value = -1; + ActivateSensor(_fullscreenFps); } } @@ -107,12 +147,12 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (_currentOverdriveApiLevel >= 6) { - if (AtiAdlxx.ADL2_Main_Control_Create(AtiAdlxx.Main_Memory_Alloc, adapterIndex, ref _context) == AtiAdlxx.ADLStatus.ADL_OK) + if (AtiAdlxx.ADL2_Main_Control_Create(AtiAdlxx.Main_Memory_Alloc, _adapterIndex, ref _context) == AtiAdlxx.ADLStatus.ADL_OK) _context = IntPtr.Zero; } - AtiAdlxx.ADLFanSpeedInfo fanSpeedInfo = new AtiAdlxx.ADLFanSpeedInfo(); - if (AtiAdlxx.ADL_Overdrive5_FanSpeedInfo_Get(adapterIndex, 0, ref fanSpeedInfo) != AtiAdlxx.ADLStatus.ADL_OK) + AtiAdlxx.ADLFanSpeedInfo fanSpeedInfo = new(); + if (AtiAdlxx.ADL_Overdrive5_FanSpeedInfo_Get(_adapterIndex, 0, ref fanSpeedInfo) != AtiAdlxx.ADLStatus.ADL_OK) { fanSpeedInfo.MaxPercent = 100; fanSpeedInfo.MinPercent = 0; @@ -139,11 +179,9 @@ namespace LibreHardwareMonitor.Hardware.Gpu { if (control.ControlMode == ControlMode.Software) { - AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new AtiAdlxx.ADLFanSpeedValue + AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() { - SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, - Flags = AtiAdlxx.ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED, - FanSpeed = (int)control.SoftwareValue + SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, Flags = AtiAdlxx.ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED, FanSpeed = (int)control.SoftwareValue }; AtiAdlxx.ADL_Overdrive5_FanSpeed_Set(_adapterIndex, 0, ref fanSpeedValue); @@ -177,16 +215,35 @@ namespace LibreHardwareMonitor.Hardware.Gpu public override void Update() { - if(_framemetricsStarted) + if (_windowsDeviceName != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_windowsDeviceName, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_gpuDedicatedMemoryUsage); + ActivateSensor(_gpuSharedMemoryUsage); + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; + + _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_gpuNodeUsage[node.Id]); + } + } + + if (_frameMetricsStarted) { float framesPerSecond = 0; if (AtiAdlxx.ADL2_Adapter_FrameMetrics_Get(_context, _adapterIndex, 0, ref framesPerSecond) == AtiAdlxx.ADLStatus.ADL_OK) { - _fullscreenFPS.Value = framesPerSecond; + _fullscreenFps.Value = framesPerSecond; } } - if (_currentOverdriveApiLevel < 8) + if (_overdriveApiSupported) { if (_currentOverdriveApiLevel >= 6) { @@ -217,7 +274,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu } else { - AtiAdlxx.ADLPMLogDataOutput logDataOutput = new AtiAdlxx.ADLPMLogDataOutput(); + AtiAdlxx.ADLPMLogDataOutput logDataOutput = new(); if (AtiAdlxx.ADL2_New_QueryPMLogData_Get(_context, _adapterIndex, ref logDataOutput) == AtiAdlxx.ADLStatus.ADL_OK) { GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_EDGE, _temperatureCore); @@ -266,7 +323,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private void GetOD5CurrentActivity() { - AtiAdlxx.ADLPMActivity adlpmActivity = new AtiAdlxx.ADLPMActivity(); + AtiAdlxx.ADLPMActivity adlpmActivity = new(); if (AtiAdlxx.ADL_Overdrive5_CurrentActivity_Get(_adapterIndex, ref adlpmActivity) == AtiAdlxx.ADLStatus.ADL_OK) { if (adlpmActivity.EngineClock > 0) @@ -313,7 +370,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private void GetOD5FanSpeed(int speedType, Sensor sensor) { - AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new AtiAdlxx.ADLFanSpeedValue { SpeedType = speedType }; + AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() { SpeedType = speedType }; if (AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterIndex, 0, ref fanSpeedValue) == AtiAdlxx.ADLStatus.ADL_OK) { sensor.Value = fanSpeedValue.FanSpeed; @@ -325,17 +382,17 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } - private void GetOD5Temperature(Sensor _temperatureCore) + private void GetOD5Temperature(Sensor temperatureCore) { - AtiAdlxx.ADLTemperature temperature = new AtiAdlxx.ADLTemperature(); + AtiAdlxx.ADLTemperature temperature = new(); if (AtiAdlxx.ADL_Overdrive5_Temperature_Get(_adapterIndex, 0, ref temperature) == AtiAdlxx.ADLStatus.ADL_OK) { - _temperatureCore.Value = 0.001f * temperature.Temperature; - ActivateSensor(_temperatureCore); + temperatureCore.Value = 0.001f * temperature.Temperature; + ActivateSensor(temperatureCore); } else { - _temperatureCore.Value = null; + temperatureCore.Value = null; } } @@ -344,6 +401,8 @@ namespace LibreHardwareMonitor.Hardware.Gpu /// /// The type. /// The sensor. + /// The minimum temperature. + /// The scale. private void GetODNTemperature(AtiAdlxx.ADLODNTemperatureType type, Sensor sensor, double minTemperature = -200, double scale = 1) { // If a sensor isn't available, some cards report 54000 degrees C. 110C is expected for Navi, so 100 more than that should be enough to use as a maximum. @@ -410,7 +469,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (_fanControl.ControlMode != ControlMode.Undefined) SetDefaultFanSpeed(); - if (_framemetricsStarted) + if (_frameMetricsStarted) AtiAdlxx.ADL2_Adapter_FrameMetrics_Stop(_context, _adapterIndex, 0); if (_context != IntPtr.Zero) diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs index 5311a32..0914d02 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs @@ -80,12 +80,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu } if (!found) - _hardware.Add(new AmdGpu( - adapterInfo[i].AdapterName.Trim(), - adapterInfo[i].AdapterIndex, - adapterInfo[i].BusNumber, - adapterInfo[i].DeviceNumber, - settings)); + _hardware.Add(new AmdGpu(adapterInfo[i], settings)); } _report.AppendLine(); diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index 5bb0d50..117e940 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -8,6 +8,7 @@ using System; using System.Globalization; using System.Text; using LibreHardwareMonitor.Interop; +using Microsoft.Win32; namespace LibreHardwareMonitor.Hardware.Gpu { @@ -19,17 +20,25 @@ namespace LibreHardwareMonitor.Hardware.Gpu private readonly NvApi.NvDisplayHandle? _displayHandle; private readonly Sensor _fan; private readonly Control _fanControl; + 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 _memoryUsed; + private readonly int _nodeSensorIndex; private readonly NvidiaML.NvmlDevice? _nvmlDevice; private readonly Sensor _pcieThroughputRx; private readonly Sensor _pcieThroughputTx; 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) @@ -120,6 +129,101 @@ namespace LibreHardwareMonitor.Hardware.Gpu _pcieThroughputRx = new Sensor("GPU PCIe Rx", 0, SensorType.Throughput, this, settings); _pcieThroughputTx = new Sensor("GPU PCIe Tx", 1, SensorType.Throughput, this, settings); + + if (!Software.OperatingSystem.IsUnix) + { + NvidiaML.NvmlPciInfo? pciInfo = NvidiaML.NvmlDeviceGetPciInfo(_nvmlDevice.Value); + + if (pciInfo is { } pci) + { + string[] deviceIdentifiers = D3DDisplayDevice.GetDeviceIdentifiers(); + if (deviceIdentifiers != null) + { + foreach (string deviceIdentifier in deviceIdentifiers) + { + if (deviceIdentifier.IndexOf("VEN_" + pci.pciVendorId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && + deviceIdentifier.IndexOf("DEV_" + pci.pciDeviceId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && + deviceIdentifier.IndexOf("SUBSYS_" + pci.pciSubSystemId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1) + { + bool isMatch = false; + + try + { + if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nvlddmkm\Enum", adapterIndex.ToString(), null) is string adapterPnpId) + { + if (deviceIdentifier.IndexOf(adapterPnpId.Replace('\\', '#'), StringComparison.OrdinalIgnoreCase) != -1) + isMatch = true; + } + } + catch + { + // Ignored. + } + + if (!isMatch) + { + try + { + string path = deviceIdentifier; + if (path.StartsWith(@"\\?\")) + path = path.Substring(4); + + path = path.Replace('#', '\\'); + int index = path.IndexOf('{'); + if (index != -1) + path = path.Substring(0, index); + + path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + path; + + if (Registry.GetValue(path, "LocationInformation", null) is string locationInformation) + { + // For example: + // @System32\drivers\pci.sys,#65536;PCI bus %1, device %2, function %3;(38,0,0) + + index = locationInformation.IndexOf('('); + if (index != -1) + { + index++; + int secondIndex = locationInformation.IndexOf(',', index); + if (secondIndex != -1) + { + string bus = locationInformation.Substring(index, secondIndex - index); + + if (pci.bus.ToString() == bus) + isMatch = true; + } + } + } + } + catch + { + // Ignored. + } + } + + if (isMatch && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceIdentifier, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _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); + + _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + _gpuNodeUsage[node.Id] = new Sensor(node.Name, _nodeSensorIndex++, SensorType.Load, this, settings); + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + } + } + } + } + } + } + } } } @@ -143,7 +247,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private NvApi.NvGPUThermalSettings GetThermalSettings() { - NvApi.NvGPUThermalSettings settings = new NvApi.NvGPUThermalSettings + 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] }; @@ -170,7 +274,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private NvApi.NvGPUCoolerSettings GetCoolerSettings() { - NvApi.NvGPUCoolerSettings settings = new NvApi.NvGPUCoolerSettings { Version = NvApi.GPU_COOLER_SETTINGS_VER, Cooler = new NvApi.NvCooler[NvApi.MAX_COOLER_PER_GPU] }; + 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; @@ -181,7 +285,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private uint[] GetClocks() { - NvApi.NvClocks allClocks = new NvApi.NvClocks { Version = NvApi.GPU_CLOCKS_VER, Clock = new uint[NvApi.MAX_CLOCKS_PER_GPU] }; + 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; @@ -192,6 +296,25 @@ namespace LibreHardwareMonitor.Hardware.Gpu public override void Update() { + if (_windowsDeviceName != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_windowsDeviceName, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_gpuDedicatedMemoryUsage); + ActivateSensor(_gpuSharedMemoryUsage); + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; + + _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_gpuNodeUsage[node.Id]); + } + } + 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) @@ -228,7 +351,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } - NvApi.NvPStates states = new NvApi.NvPStates { Version = NvApi.GPU_PSTATES_VER, PStates = new NvApi.NvPState[NvApi.MAX_PSTATES_PER_GPU] }; + 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++) @@ -242,7 +365,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu } else { - NvApi.NvUsages usages = new NvApi.NvUsages { Version = NvApi.GPU_USAGES_VER, Usage = new uint[NvApi.MAX_USAGES_PER_GPU] }; + 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) { _loads[0].Value = usages.Usage[2]; @@ -282,7 +405,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } - NvApi.NvMemoryInfo memoryInfo = new NvApi.NvMemoryInfo { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; + 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) { uint totalMemory = memoryInfo.Values[0]; @@ -326,7 +449,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu public override string GetReport() { - StringBuilder r = new StringBuilder(); + StringBuilder r = new(); r.AppendLine("Nvidia GPU"); r.AppendLine(); @@ -335,7 +458,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (_displayHandle.HasValue && NvApi.NvAPI_GetDisplayDriverVersion != null) { - NvApi.NvDisplayDriverVersion driverVersion = new NvApi.NvDisplayDriverVersion { Version = NvApi.DISPLAY_DRIVER_VERSION_VER }; + 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: "); @@ -369,7 +492,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (NvApi.NvAPI_GPU_GetThermalSettings != null) { - NvApi.NvGPUThermalSettings settings = new NvApi.NvGPUThermalSettings + 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] }; @@ -399,7 +522,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (NvApi.NvAPI_GPU_GetAllClocks != null) { - NvApi.NvClocks allClocks = new NvApi.NvClocks { Version = NvApi.GPU_CLOCKS_VER, Clock = new uint[NvApi.MAX_CLOCKS_PER_GPU] }; + 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); r.AppendLine("Clocks"); @@ -442,7 +565,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (NvApi.NvAPI_GPU_GetPStates != null) { - NvApi.NvPStates states = new NvApi.NvPStates { Version = NvApi.GPU_PSTATES_VER, PStates = new NvApi.NvPState[NvApi.MAX_PSTATES_PER_GPU] }; + 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"); @@ -466,7 +589,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (NvApi.NvAPI_GPU_GetUsages != null) { - NvApi.NvUsages usages = new NvApi.NvUsages { Version = NvApi.GPU_USAGES_VER, Usage = new uint[NvApi.MAX_USAGES_PER_GPU] }; + 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); r.AppendLine("Usages"); @@ -490,7 +613,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu if (NvApi.NvAPI_GPU_GetCoolerSettings != null) { - NvApi.NvGPUCoolerSettings settings = new NvApi.NvGPUCoolerSettings { Version = NvApi.GPU_COOLER_SETTINGS_VER, Cooler = new NvApi.NvCooler[NvApi.MAX_COOLER_PER_GPU] }; + 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(); @@ -523,11 +646,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu 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] - }; + 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); @@ -537,16 +656,30 @@ namespace LibreHardwareMonitor.Hardware.Gpu { 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); + 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 @@ -554,12 +687,13 @@ namespace LibreHardwareMonitor.Hardware.Gpu r.Append(" Status: "); r.AppendLine(status.ToString()); } + r.AppendLine(); } if (NvApi.NvAPI_GPU_GetMemoryInfo != null && _displayHandle.HasValue) { - NvApi.NvMemoryInfo memoryInfo = new NvApi.NvMemoryInfo { Version = NvApi.GPU_MEMORY_INFO_VER, Values = new uint[NvApi.MAX_MEMORY_VALUES_PER_GPU] }; + 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); r.AppendLine("Memory Info"); @@ -583,7 +717,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private void SoftwareControlValueChanged(IControl control) { - NvApi.NvGPUCoolerLevels coolerLevels = new NvApi.NvGPUCoolerLevels { Version = NvApi.GPU_COOLER_LEVELS_VER, Levels = new NvApi.NvLevel[NvApi.MAX_COOLER_PER_GPU] }; + 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); @@ -608,7 +742,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu private void SetDefaultFanSpeed() { - NvApi.NvGPUCoolerLevels coolerLevels = new NvApi.NvGPUCoolerLevels { Version = NvApi.GPU_COOLER_LEVELS_VER, Levels = new NvApi.NvLevel[NvApi.MAX_COOLER_PER_GPU] }; + 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); } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs index 7f37984..b515f5b 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs @@ -13,8 +13,8 @@ namespace LibreHardwareMonitor.Hardware.Gpu { internal class NvidiaGroup : IGroup { - private readonly List _hardware = new List(); - private readonly StringBuilder _report = new StringBuilder(); + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); public NvidiaGroup(ISettings settings) { @@ -54,7 +54,7 @@ namespace LibreHardwareMonitor.Hardware.Gpu int i = 0; while (status == NvApi.NvStatus.OK) { - NvApi.NvDisplayHandle displayHandle = new NvApi.NvDisplayHandle(); + NvApi.NvDisplayHandle displayHandle = new(); status = NvApi.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle); i++; diff --git a/LibreHardwareMonitorLib/Interop/CfgMgr32.cs b/LibreHardwareMonitorLib/Interop/CfgMgr32.cs new file mode 100644 index 0000000..b5ba559 --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/CfgMgr32.cs @@ -0,0 +1,28 @@ +// 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. + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +using System; +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Interop +{ + internal static class CfgMgr32 + { + internal const uint CM_GET_DEVICE_INTERFACE_LIST_PRESENT = 0; + internal const int CR_SUCCESS = 0; + internal static Guid GUID_DISPLAY_DEVICE_ARRIVAL = new("1CA05180-A699-450A-9A0C-DE4FBE3DDD89"); + + internal const string DllName = "CfgMgr32.dll"; + + [DllImport(DllName, CharSet = CharSet.Unicode)] + internal static extern uint CM_Get_Device_Interface_List_Size(out uint size, ref Guid interfaceClassGuid, string deviceID, uint flags); + + [DllImport(DllName, CharSet = CharSet.Unicode)] + internal static extern uint CM_Get_Device_Interface_List(ref Guid interfaceClassGuid, string deviceID, char[] buffer, uint bufferLength, uint flags); + } +} diff --git a/LibreHardwareMonitorLib/Interop/D3dkmdt.cs b/LibreHardwareMonitorLib/Interop/D3dkmdt.cs new file mode 100644 index 0000000..2dc3744 --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/D3dkmdt.cs @@ -0,0 +1,48 @@ +// 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. + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Interop +{ + internal static class D3dkmdt + { + internal enum DXGK_ENGINE_TYPE + { + DXGK_ENGINE_TYPE_OTHER = 0, + DXGK_ENGINE_TYPE_3D = 1, + DXGK_ENGINE_TYPE_VIDEO_DECODE = 2, + DXGK_ENGINE_TYPE_VIDEO_ENCODE = 3, + DXGK_ENGINE_TYPE_VIDEO_PROCESSING = 4, + DXGK_ENGINE_TYPE_SCENE_ASSEMBLY = 5, + DXGK_ENGINE_TYPE_COPY = 6, + DXGK_ENGINE_TYPE_OVERLAY = 7, + DXGK_ENGINE_TYPE_CRYPTO, + DXGK_ENGINE_TYPE_MAX + } + + [StructLayout(LayoutKind.Sequential)] + internal struct DXGK_NODEMETADATA_FLAGS + { + public uint Value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] + internal struct DXGK_NODEMETADATA + { + public DXGK_ENGINE_TYPE EngineType; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string FriendlyName; + + public DXGK_NODEMETADATA_FLAGS Flags; + public byte GpuMmuSupported; + public byte IoMmuSupported; + } + } +} diff --git a/LibreHardwareMonitorLib/Interop/D3dkmth.cs b/LibreHardwareMonitorLib/Interop/D3dkmth.cs new file mode 100644 index 0000000..117801b --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/D3dkmth.cs @@ -0,0 +1,563 @@ +// 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. + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +using System; +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Interop +{ + internal static class D3dkmth + { + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_CLOSEADAPTER + { + public uint hAdapter; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYADAPTERINFO + { + public uint hAdapter; + public KMTQUERYADAPTERINFOTYPE Type; + public IntPtr pPrivateDriverData; + public int PrivateDriverDataSize; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_OPENADAPTERFROMDEVICENAME + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pDeviceName; + + public uint hAdapter; + public WinNt.LUID AdapterLuid; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_ADAPTERTYPE + { + public D3DKMT_ADAPTERTYPE_FLAGS Value; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT + { + public uint SegmentId; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_NODE + { + public uint NodeId; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE + { + public uint VidPnSourceId; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER + { + public uint NbCall; + public uint NbAllocationsReferenced; + public uint MaxNbAllocationsReferenced; + public uint NbNULLReference; + public uint NbWriteReference; + public uint NbRenamedAllocationsReferenced; + public uint NbIterationSearchingRenamedAllocation; + public uint NbLockedAllocationReferenced; + public uint NbAllocationWithValidPrepatchingInfoReferenced; + public uint NbAllocationWithInvalidPrepatchingInfoReferenced; + public uint NbDMABufferSuccessfullyPrePatched; + public uint NbPrimariesReferencesOverflow; + public uint NbAllocationWithNonPreferredResources; + public uint NbAllocationInsertedInMigrationTable; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_SEGMENTSIZEINFO + { + public ulong DedicatedVideoMemorySize; + public ulong DedicatedSystemMemorySize; + public ulong SharedSystemMemorySize; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_RENAMING + { + public uint NbAllocationsRenamed; + public uint NbAllocationsShrinked; + public uint NbRenamedBuffer; + public uint MaxRenamingListLength; + public uint NbFailuresDueToRenamingLimit; + public uint NbFailuresDueToCreateAllocation; + public uint NbFailuresDueToOpenAllocation; + public uint NbFailuresDueToLowResource; + public uint NbFailuresDueToNonRetiredLimit; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_COUNTER + { + public uint Count; + public ulong Bytes; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PREPRATION + { + public uint BroadcastStall; + public uint NbDMAPrepared; + public uint NbDMAPreparedLongPath; + public uint ImmediateHighestPreparationPass; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PAGING_FAULT + { + public D3DKMT_QUERYSTATISTICS_COUNTER Faults; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail; + + public uint AllocationsUnresetSuccessRead; + public uint AllocationsUnresetFailRead; + + public D3DKMT_QUERYSTATISTICS_COUNTER Evictions; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER + { + public ulong BytesFilled; + public ulong BytesDiscarded; + public ulong BytesMappedIntoAperture; + public ulong BytesUnmappedFromAperture; + public ulong BytesTransferredFromMdlToMemory; + public ulong BytesTransferredFromMemoryToMdl; + public ulong BytesTransferredFromApertureToMemory; + public ulong BytesTransferredFromMemoryToAperture; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE + { + public uint NbRangesAcquired; + public uint NbRangesReleased; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_LOCKS + { + public uint NbLocks; + public uint NbLocksWaitFlag; + public uint NbLocksDiscardFlag; + public uint NbLocksNoOverwrite; + public uint NbLocksNoReadSync; + public uint NbLocksLinearization; + public uint NbComplexLocks; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_ALLOCATIONS + { + public D3DKMT_QUERYSTATISTICS_COUNTER Created; + public D3DKMT_QUERYSTATISTICS_COUNTER Destroyed; + public D3DKMT_QUERYSTATISTICS_COUNTER Opened; + public D3DKMT_QUERYSTATISTICS_COUNTER Closed; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_TERMINATIONS + { + public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared; + public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared; + public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared; + public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION + { + public uint NbSegments; + public uint NodeCount; + public uint VidPnSourceCount; + + public uint VSyncEnabled; + public uint TdrDetectedCount; + + public long ZeroLengthDmaBuffers; + public ulong RestartedPeriod; + + public D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer; + public D3DKMT_QUERYSTATISTICS_RENAMING Renaming; + public D3DKMT_QUERYSTATISTICS_PREPRATION Preparation; + public D3DKMT_QUERYSTATISTICS_PAGING_FAULT PagingFault; + public D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER PagingTransfer; + public D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE SwizzlingRange; + public D3DKMT_QUERYSTATISTICS_LOCKS Locks; + public D3DKMT_QUERYSTATISTICS_ALLOCATIONS Allocations; + public D3DKMT_QUERYSTATISTICS_TERMINATIONS Terminations; + + private readonly ulong Reserved; + private readonly ulong Reserved1; + private readonly ulong Reserved2; + private readonly ulong Reserved3; + private readonly ulong Reserved4; + private readonly ulong Reserved5; + private readonly ulong Reserved6; + private readonly ulong Reserved7; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_MEMORY + { + public ulong TotalBytesEvicted; + public uint AllocsCommitted; + public uint AllocsResident; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION + { + public ulong CommitLimit; + public ulong BytesCommitted; + public ulong BytesResident; + public D3DKMT_QUERYSTATISTICS_MEMORY Memory; + public uint Aperture; // boolean + public fixed ulong TotalBytesEvictedByPriority[5]; // D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX + public ulong SystemMemoryEndAddress; + public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS PowerFlags; + public fixed ulong Reserved[6]; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS + { + [FieldOffset(0)] + public ulong PreservedDuringStandby; + + [FieldOffset(1)] + public ulong PreservedDuringHibernate; + + [FieldOffset(2)] + public ulong PartiallyPreservedDuringHibernate; + + [FieldOffset(3)] + public ulong Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY + { + public uint AllocsCommitted; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn0; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn1; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn2; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn3; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn4; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred; + public ulong TotalBytesEvictedDueToPreparation; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY + { + public ulong UseMRU; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION + { + public ulong BytesCommitted; + public ulong MaximumWorkingSet; + public ulong MinimumWorkingSet; + + public uint NbReferencedAllocationEvictedInPeriod; + + public D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory; + public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy; + + public fixed ulong Reserved[8]; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION + { + public uint PreemptionCounter; + public uint PreemptionCounter1; + public uint PreemptionCounter2; + public uint PreemptionCounter3; + public uint PreemptionCounter4; + public uint PreemptionCounter5; + public uint PreemptionCounter6; + public uint PreemptionCounter7; + public uint PreemptionCounter8; + public uint PreemptionCounter9; + public uint PreemptionCounter10; + public uint PreemptionCounter11; + public uint PreemptionCounter12; + public uint PreemptionCounter13; + public uint PreemptionCounter14; + public uint PreemptionCounter15; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION + { + public WinNt.LARGE_INTEGER RunningTime; // 100ns + public uint ContextSwitch; + readonly D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics; + readonly D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics; + private fixed ulong Reserved[8]; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_NODE_INFORMATION + { + public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global + + public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread + + //public UInt32 NodeId; // Win10 + public fixed ulong Reserved[8]; + } + + internal struct D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION + { + public uint PacketSubmitted; + public uint PacketCompleted; + public uint PacketPreempted; + public uint PacketFaulted; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION + { + public uint PacketSubmited; + public uint PacketCompleted; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION + { + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket1; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket2; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket3; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket4; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket5; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket6; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket7; + + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket1; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket2; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket3; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_RESULT + { + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; + + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; + + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; + + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; + + // D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; + // D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; + // D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 + // D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP_INFORMATION ProcessSegmentGroupInformation; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT + { + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment; + + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment; + + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode; + + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode; + + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource; + + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS + { + public D3DKMT_QUERYSTATISTICS_TYPE Type; + public WinNt.LUID AdapterLuid; + public uint ProcessHandle; + public D3DKMT_QUERYSTATISTICS_RESULT QueryResult; + public D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT QueryElement; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct D3DKMT_NODEMETADATA + { + public uint NodeOrdinalAndAdapterIndex; + public D3dkmdt.DXGK_NODEMETADATA NodeData; + } + + [Flags] + internal enum D3DKMT_ADAPTERTYPE_FLAGS : uint + { + RenderSupported = 0, + DisplaySupported = 1, + SoftwareDevice = 2, + PostDevice = 4, + HybridDiscrete = 8, + HybridIntegrated = 16, + IndirectDisplayDevice = 32, + Paravirtualized = 64, + ACGSupported = 128, + SupportSetTimingsFromVidPn = 256, + Detachable = 512, + ComputeOnly = 1024, + Prototype = 2045 + } + + internal enum D3DKMT_QUERYSTATISTICS_TYPE + { + D3DKMT_QUERYSTATISTICS_ADAPTER, + D3DKMT_QUERYSTATISTICS_PROCESS, + D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER, + D3DKMT_QUERYSTATISTICS_SEGMENT, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT, + D3DKMT_QUERYSTATISTICS_NODE, + D3DKMT_QUERYSTATISTICS_PROCESS_NODE, + D3DKMT_QUERYSTATISTICS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP, + D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER + } + + internal enum D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE + { + D3DKMT_ClientRenderBuffer = 0, + D3DKMT_ClientPagingBuffer = 1, + D3DKMT_SystemPagingBuffer = 2, + D3DKMT_SystemPreemptionBuffer = 3, + D3DKMT_DmaPacketTypeMax + } + + internal enum KMTQUERYADAPTERINFOTYPE + { + KMTQAITYPE_UMDRIVERPRIVATE = 0, + KMTQAITYPE_UMDRIVERNAME = 1, + KMTQAITYPE_UMOPENGLINFO = 2, + KMTQAITYPE_GETSEGMENTSIZE = 3, + KMTQAITYPE_ADAPTERGUID = 4, + KMTQAITYPE_FLIPQUEUEINFO = 5, + KMTQAITYPE_ADAPTERADDRESS = 6, + KMTQAITYPE_SETWORKINGSETINFO = 7, + KMTQAITYPE_ADAPTERREGISTRYINFO = 8, + KMTQAITYPE_CURRENTDISPLAYMODE = 9, + KMTQAITYPE_MODELIST = 10, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS = 11, + KMTQAITYPE_VIRTUALADDRESSINFO = 12, + KMTQAITYPE_DRIVERVERSION = 13, + KMTQAITYPE_ADAPTERTYPE = 15, + KMTQAITYPE_OUTPUTDUPLCONTEXTSCOUNT = 16, + KMTQAITYPE_WDDM_1_2_CAPS = 17, + KMTQAITYPE_UMD_DRIVER_VERSION = 18, + KMTQAITYPE_DIRECTFLIP_SUPPORT = 19, + KMTQAITYPE_MULTIPLANEOVERLAY_SUPPORT = 20, + KMTQAITYPE_DLIST_DRIVER_NAME = 21, + KMTQAITYPE_WDDM_1_3_CAPS = 22, + KMTQAITYPE_MULTIPLANEOVERLAY_HUD_SUPPORT = 23, + KMTQAITYPE_WDDM_2_0_CAPS = 24, + KMTQAITYPE_NODEMETADATA = 25, + KMTQAITYPE_CPDRIVERNAME = 26, + KMTQAITYPE_XBOX = 27, + KMTQAITYPE_INDEPENDENTFLIP_SUPPORT = 28, + KMTQAITYPE_MIRACASTCOMPANIONDRIVERNAME = 29, + KMTQAITYPE_PHYSICALADAPTERCOUNT = 30, + KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, + KMTQAITYPE_DRIVERCAPS_EXT = 32, + KMTQAITYPE_QUERY_MIRACAST_DRIVER_TYPE = 33, + KMTQAITYPE_QUERY_GPUMMU_CAPS = 34, + KMTQAITYPE_QUERY_MULTIPLANEOVERLAY_DECODE_SUPPORT = 35, + KMTQAITYPE_QUERY_HW_PROTECTION_TEARDOWN_COUNT = 36, + KMTQAITYPE_QUERY_ISBADDRIVERFORHWPROTECTIONDISABLED = 37, + KMTQAITYPE_MULTIPLANEOVERLAY_SECONDARY_SUPPORT = 38, + KMTQAITYPE_INDEPENDENTFLIP_SECONDARY_SUPPORT = 39, + KMTQAITYPE_PANELFITTER_SUPPORT = 40, + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, + KMTQAITYPE_GETSEGMENTGROUPSIZE = 42, + KMTQAITYPE_MPO3DDI_SUPPORT = 43, + KMTQAITYPE_HWDRM_SUPPORT = 44, + KMTQAITYPE_MPOKERNELCAPS_SUPPORT = 45, + KMTQAITYPE_MULTIPLANEOVERLAY_STRETCH_SUPPORT = 46, + KMTQAITYPE_GET_DEVICE_VIDPN_OWNERSHIP_INFO = 47, + KMTQAITYPE_QUERYREGISTRY = 48, + KMTQAITYPE_KMD_DRIVER_VERSION = 49, + KMTQAITYPE_BLOCKLIST_KERNEL = 50, + KMTQAITYPE_BLOCKLIST_RUNTIME = 51, + KMTQAITYPE_ADAPTERGUID_RENDER = 52, + KMTQAITYPE_ADAPTERADDRESS_RENDER = 53, + KMTQAITYPE_ADAPTERREGISTRYINFO_RENDER = 54, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS_RENDER = 55, + KMTQAITYPE_DRIVERVERSION_RENDER = 56, + KMTQAITYPE_ADAPTERTYPE_RENDER = 57, + KMTQAITYPE_WDDM_1_2_CAPS_RENDER = 58, + KMTQAITYPE_WDDM_1_3_CAPS_RENDER = 59, + KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, + KMTQAITYPE_NODEPERFDATA = 61, + KMTQAITYPE_ADAPTERPERFDATA = 62, + KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, + KMTQUITYPE_GPUVERSION = 64, + KMTQAITYPE_DRIVER_DESCRIPTION = 65, + KMTQAITYPE_DRIVER_DESCRIPTION_RENDER = 66, + KMTQAITYPE_SCANOUT_CAPS = 67, + KMTQAITYPE_DISPLAY_UMDRIVERNAME = 71, + KMTQAITYPE_PARAVIRTUALIZATION_RENDER = 68, + KMTQAITYPE_SERVICENAME = 69, + KMTQAITYPE_WDDM_2_7_CAPS = 70, + KMTQAITYPE_TRACKEDWORKLOAD_SUPPORT = 72, + } + } +} diff --git a/LibreHardwareMonitorLib/Interop/Gdi32.cs b/LibreHardwareMonitorLib/Interop/Gdi32.cs new file mode 100644 index 0000000..1f01eb2 --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/Gdi32.cs @@ -0,0 +1,29 @@ +// 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. + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Interop +{ + internal static class Gdi32 + { + internal const string DllName = "Gdi32.dll"; + + [DllImport(DllName, ExactSpelling = true)] + internal static extern uint D3DKMTCloseAdapter(ref D3dkmth.D3DKMT_CLOSEADAPTER closeAdapter); + + [DllImport(DllName, ExactSpelling = true)] + internal static extern uint D3DKMTOpenAdapterFromDeviceName(ref D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName); + + [DllImport(DllName, ExactSpelling = true)] + internal static extern uint D3DKMTQueryAdapterInfo(ref D3dkmth.D3DKMT_QUERYADAPTERINFO queryAdapterInfo); + + [DllImport(DllName, ExactSpelling = true)] + internal static extern uint D3DKMTQueryStatistics(ref D3dkmth.D3DKMT_QUERYSTATISTICS queryStatistics); + } +} diff --git a/LibreHardwareMonitorLib/Interop/NvidiaML.cs b/LibreHardwareMonitorLib/Interop/NvidiaML.cs index 7d12901..0d60565 100644 --- a/LibreHardwareMonitorLib/Interop/NvidiaML.cs +++ b/LibreHardwareMonitorLib/Interop/NvidiaML.cs @@ -14,291 +14,25 @@ namespace LibreHardwareMonitor.Interop private const string LinuxDllName = "nvidia-ml"; private const string WindowsDllName = "nvml.dll"; - private static readonly object SyncRoot = new object(); + private static readonly object _syncRoot = new(); + + private static IntPtr _windowsDll; private static WindowsNvmlGetHandleDelegate _windowsNvmlDeviceGetHandleByIndex; - private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage; - private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate; private static WindowsNvmlGetHandleByPciBusIdDelegate _windowsNvmlDeviceGetHandleByPciBusId; + private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate; + private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage; + private static WindowsNvmlDeviceGetPciInfo _windowsNvmlDeviceGetPciInfo; private static WindowsNvmlDelegate _windowsNvmlInit; private static WindowsNvmlDelegate _windowsNvmlShutdown; - private static IntPtr WindowsDll; - - internal static bool IsAvailable { get; private set; } - - internal static bool Initialize() - { - lock (SyncRoot) - { - if (IsAvailable) - { - return true; - } - - if (Software.OperatingSystem.IsUnix) - { - try - { - IsAvailable = nvmlInit() == NvmlReturn.Success; - } - catch (DllNotFoundException) - { } - catch (EntryPointNotFoundException) - { - try - { - IsAvailable = nvmlInitLegacy() == NvmlReturn.Success; - } - catch (EntryPointNotFoundException) - { } - } - } - else if (IsNvmlCompatibleWindowsVersion()) - { - // Attempt to load the Nvidia Management Library from the - // windows standard search order for applications. This will - // help installations that either have the library in - // %windir%/system32 or provide their own library - WindowsDll = Kernel32.LoadLibrary(WindowsDllName); - - // If there is no dll in the path, then attempt to load it - // from program files - if (WindowsDll == IntPtr.Zero) - { - string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%"); - string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName); - - WindowsDll = Kernel32.LoadLibrary(dllPath); - } - - IsAvailable = (WindowsDll != IntPtr.Zero) - && InitialiseDelegates() - && (_windowsNvmlInit() == NvmlReturn.Success); - } - - return IsAvailable; - } - } - - private static bool IsNvmlCompatibleWindowsVersion() - { - return Software.OperatingSystem.Is64Bit && ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)); - } - - private static bool InitialiseDelegates() - { - IntPtr nvmlInit = Kernel32.GetProcAddress(WindowsDll, "nvmlInit_v2"); - - if (nvmlInit != IntPtr.Zero) - { - _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); - } - else - { - nvmlInit = Kernel32.GetProcAddress(WindowsDll, "nvmlInit"); - if (nvmlInit != IntPtr.Zero) - _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); - else - return false; - } - - IntPtr nvmlShutdown = Kernel32.GetProcAddress(WindowsDll, "nvmlShutdown"); - if (nvmlShutdown != IntPtr.Zero) - _windowsNvmlShutdown = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlShutdown, typeof(WindowsNvmlDelegate)); - else - return false; - - - IntPtr nvmlGetHandle = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetHandleByIndex_v2"); - if (nvmlGetHandle != IntPtr.Zero) - { - _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); - } - else - { - nvmlGetHandle = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetHandleByIndex"); - if (nvmlGetHandle != IntPtr.Zero) - _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); - else - return false; - } - - IntPtr nvmlGetPowerUsage = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetPowerUsage"); - if (nvmlGetPowerUsage != IntPtr.Zero) - _windowsNvmlDeviceGetPowerUsage = (WindowsNvmlGetPowerUsageDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPowerUsage, typeof(WindowsNvmlGetPowerUsageDelegate)); - else - return false; - - IntPtr nvmlGetPcieThroughput = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetPcieThroughput"); - if (nvmlGetPcieThroughput != IntPtr.Zero) - _windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate)); - else - return false; - - IntPtr nvmlGetHandlePciBus = Kernel32.GetProcAddress(WindowsDll, "nvmlDeviceGetHandleByPciBusId_v2"); - if (nvmlGetHandlePciBus != IntPtr.Zero) - _windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate)); - else - return false; - - return true; - } - - internal static void Close() - { - lock (SyncRoot) - { - if (IsAvailable) - { - if (Software.OperatingSystem.IsUnix) - { - nvmlShutdown(); - } - else if (WindowsDll != IntPtr.Zero) - { - _windowsNvmlShutdown(); - Kernel32.FreeLibrary(WindowsDll); - } - - IsAvailable = false; - } - } - } - - internal static NvmlDevice? NvmlDeviceGetHandleByIndex(int index) - { - if (IsAvailable) - { - NvmlDevice nvmlDevice; - if (Software.OperatingSystem.IsUnix) - { - try - { - if (nvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } - catch (EntryPointNotFoundException) - { - if (nvmlDeviceGetHandleByIndexLegacy(index, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } - } - else if (_windowsNvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) - { - return nvmlDevice; - } - } - - return null; - } - - - internal static NvmlDevice? NvmlDeviceGetHandleByPciBusId(string pciBusId) - { - if (IsAvailable) - { - NvmlDevice nvmlDevice; - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } - else if (_windowsNvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) - { - return nvmlDevice; - } - } - - return null; - } - - internal static int? NvmlDeviceGetPowerUsage(NvmlDevice nvmlDevice) - { - if (IsAvailable) - { - int powerUsage; - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) - return powerUsage; - } - else if (_windowsNvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) - { - return powerUsage; - } - } - - return null; - } - - internal static uint? NvmlDeviceGetPcieThroughput(NvmlDevice nvmlDevice, NvmlPcieUtilCounter counter) - { - if (IsAvailable) - { - uint pcieThroughput; - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) - return pcieThroughput; - } - else if (_windowsNvmlDeviceGetPcieThroughputDelegate(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) - { - return pcieThroughput; - } - } - - return null; - } - - - [DllImport(LinuxDllName, EntryPoint = "nvmlInit_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlInit(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlInit", ExactSpelling = true)] - private static extern NvmlReturn nvmlInitLegacy(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlShutdown", ExactSpelling = true)] - private static extern NvmlReturn nvmlShutdown(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByIndex(int index, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByPciBusId_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByPciBusId([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByIndexLegacy(int index, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPowerUsage", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetPowerUsage(NvmlDevice device, out int power); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPcieThroughput", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetPcieThroughput(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); - - private delegate NvmlReturn WindowsNvmlDelegate(); - - private delegate NvmlReturn WindowsNvmlGetHandleDelegate(int index, out NvmlDevice device); - - private delegate NvmlReturn WindowsNvmlGetHandleByPciBusIdDelegate([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); - - private delegate NvmlReturn WindowsNvmlGetPowerUsageDelegate(NvmlDevice device, out int power); - - private delegate NvmlReturn WindowsNvmlDeviceGetPcieThroughputDelegate(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); - - internal enum NvmlPcieUtilCounter + public enum NvmlPcieUtilCounter { TxBytes = 0, RxBytes = 1 } - [StructLayout(LayoutKind.Sequential)] - internal struct NvmlDevice - { - public IntPtr Handle; - } - - internal enum NvmlReturn + public enum NvmlReturn { /// /// The operation was successful @@ -396,9 +130,317 @@ namespace LibreHardwareMonitor.Interop InUse = 19, /// - /// An internal driver error occurred + /// An public driver error occurred /// Unknown = 999 } + + public static bool IsAvailable { get; private set; } + + public static bool Initialize() + { + lock (_syncRoot) + { + if (IsAvailable) + { + return true; + } + + if (Software.OperatingSystem.IsUnix) + { + try + { + IsAvailable = nvmlInit() == NvmlReturn.Success; + } + catch (DllNotFoundException) + { } + catch (EntryPointNotFoundException) + { + try + { + IsAvailable = nvmlInitLegacy() == NvmlReturn.Success; + } + catch (EntryPointNotFoundException) + { } + } + } + else if (IsNvmlCompatibleWindowsVersion()) + { + // Attempt to load the Nvidia Management Library from the + // windows standard search order for applications. This will + // help installations that either have the library in + // %windir%/system32 or provide their own library + _windowsDll = Kernel32.LoadLibrary(WindowsDllName); + + // If there is no dll in the path, then attempt to load it + // from program files + if (_windowsDll == IntPtr.Zero) + { + string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%"); + string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName); + + _windowsDll = Kernel32.LoadLibrary(dllPath); + } + + IsAvailable = (_windowsDll != IntPtr.Zero) && InitialiseDelegates() && (_windowsNvmlInit() == NvmlReturn.Success); + } + + return IsAvailable; + } + } + + private static bool IsNvmlCompatibleWindowsVersion() + { + return Software.OperatingSystem.Is64Bit && ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)); + } + + private static bool InitialiseDelegates() + { + IntPtr nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit_v2"); + + if (nvmlInit != IntPtr.Zero) + { + _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); + } + else + { + nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit"); + if (nvmlInit != IntPtr.Zero) + _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); + else + return false; + } + + IntPtr nvmlShutdown = Kernel32.GetProcAddress(_windowsDll, "nvmlShutdown"); + if (nvmlShutdown != IntPtr.Zero) + _windowsNvmlShutdown = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlShutdown, typeof(WindowsNvmlDelegate)); + else + return false; + + + IntPtr nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex_v2"); + if (nvmlGetHandle != IntPtr.Zero) + _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); + else + { + nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex"); + if (nvmlGetHandle != IntPtr.Zero) + _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); + else + return false; + } + + IntPtr nvmlGetPowerUsage = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPowerUsage"); + if (nvmlGetPowerUsage != IntPtr.Zero) + _windowsNvmlDeviceGetPowerUsage = (WindowsNvmlGetPowerUsageDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPowerUsage, typeof(WindowsNvmlGetPowerUsageDelegate)); + else + return false; + + + IntPtr nvmlGetPcieThroughput = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPcieThroughput"); + if (nvmlGetPcieThroughput != IntPtr.Zero) + _windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate)); + else + return false; + + + IntPtr nvmlGetHandlePciBus = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByPciBusId_v2"); + if (nvmlGetHandlePciBus != IntPtr.Zero) + _windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate)); + else + return false; + + IntPtr nvmlDeviceGetPciInfo = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPciInfo_v2"); + if (nvmlDeviceGetPciInfo != IntPtr.Zero) + _windowsNvmlDeviceGetPciInfo = (WindowsNvmlDeviceGetPciInfo)Marshal.GetDelegateForFunctionPointer(nvmlDeviceGetPciInfo, typeof(WindowsNvmlDeviceGetPciInfo)); + else + return false; + + return true; + } + + public static void Close() + { + lock (_syncRoot) + { + if (IsAvailable) + { + if (Software.OperatingSystem.IsUnix) + { + nvmlShutdown(); + } + else if (_windowsDll != IntPtr.Zero) + { + _windowsNvmlShutdown(); + Kernel32.FreeLibrary(_windowsDll); + } + + IsAvailable = false; + } + } + } + + public static NvmlDevice? NvmlDeviceGetHandleByIndex(int index) + { + if (IsAvailable) + { + NvmlDevice nvmlDevice; + if (Software.OperatingSystem.IsUnix) + { + try + { + if (nvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + catch (EntryPointNotFoundException) + { + if (nvmlDeviceGetHandleByIndexLegacy(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + } + else if (_windowsNvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + + return null; + } + + public static NvmlDevice? NvmlDeviceGetHandleByPciBusId(string pciBusId) + { + if (IsAvailable) + { + NvmlDevice nvmlDevice; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + else if (_windowsNvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + + return null; + } + + public static int? NvmlDeviceGetPowerUsage(NvmlDevice nvmlDevice) + { + if (IsAvailable) + { + int powerUsage; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) + return powerUsage; + } + else if (_windowsNvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) + return powerUsage; + } + + return null; + } + + public static uint? NvmlDeviceGetPcieThroughput(NvmlDevice nvmlDevice, NvmlPcieUtilCounter counter) + { + if (IsAvailable) + { + uint pcieThroughput; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + return pcieThroughput; + } + else if (_windowsNvmlDeviceGetPcieThroughputDelegate(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + return pcieThroughput; + } + + return null; + } + + public static NvmlPciInfo? NvmlDeviceGetPciInfo(NvmlDevice nvmlDevice) + { + if (IsAvailable) + { + var pci = new NvmlPciInfo(); + + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) + return pci; + } + else if (_windowsNvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) + return pci; + } + + return null; + } + + [DllImport(LinuxDllName, EntryPoint = "nvmlInit_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlInit(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlInit", ExactSpelling = true)] + private static extern NvmlReturn nvmlInitLegacy(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlShutdown", ExactSpelling = true)] + private static extern NvmlReturn nvmlShutdown(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByIndex(int index, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByPciBusId_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByPciBusId([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByIndexLegacy(int index, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPowerUsage", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetPowerUsage(NvmlDevice device, out int power); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPcieThroughput", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetPcieThroughput(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPciInfo_v2")] + private static extern NvmlReturn nvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); + + private delegate NvmlReturn WindowsNvmlDelegate(); + + private delegate NvmlReturn WindowsNvmlGetHandleDelegate(int index, out NvmlDevice device); + + private delegate NvmlReturn WindowsNvmlGetHandleByPciBusIdDelegate([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); + + private delegate NvmlReturn WindowsNvmlGetPowerUsageDelegate(NvmlDevice device, out int power); + + private delegate NvmlReturn WindowsNvmlDeviceGetPcieThroughputDelegate(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + + private delegate NvmlReturn WindowsNvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); + + [StructLayout(LayoutKind.Sequential)] + public struct NvmlDevice + { + public IntPtr Handle; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NvmlPciInfo + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] + public string busId; + + public uint domain; + + public uint bus; + + public uint device; + + public ushort pciVendorId; + + public ushort pciDeviceId; + + public uint pciSubSystemId; + + public uint reserved0; + public uint reserved1; + public uint reserved2; + public uint reserved3; + } } } diff --git a/LibreHardwareMonitorLib/Interop/WinNt.cs b/LibreHardwareMonitorLib/Interop/WinNt.cs new file mode 100644 index 0000000..dbc7d10 --- /dev/null +++ b/LibreHardwareMonitorLib/Interop/WinNt.cs @@ -0,0 +1,37 @@ +// 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. + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Interop +{ + internal static class WinNt + { + internal const int STATUS_SUCCESS = 0; + + [StructLayout(LayoutKind.Sequential)] + internal struct LUID + { + public readonly uint LowPart; + public readonly int HighPart; + } + + [StructLayout(LayoutKind.Explicit, Size = 8)] + internal struct LARGE_INTEGER + { + [FieldOffset(0)] + public long QuadPart; + + [FieldOffset(0)] + public uint LowPart; + + [FieldOffset(4)] + public int HighPart; + } + } +}