From 627f0a56ce1c7b5b442b8e72d12309c49be651ea Mon Sep 17 00:00:00 2001 From: Bjarni Ivarsson Date: Sat, 26 Feb 2022 10:14:09 +0100 Subject: [PATCH] Add Intel integrated GPU (#671) Thanks to @bjarniivarsson. --- LibreHardwareMonitor/Resources/intel.png | Bin 0 -> 406 bytes LibreHardwareMonitor/UI/HardwareTypeImage.cs | 3 + LibreHardwareMonitor/Utilities/HttpServer.cs | 2 + LibreHardwareMonitorLib/Hardware/Computer.cs | 21 ++- .../Hardware/Cpu/IntelCpu.cs | 5 + .../Hardware/D3DDisplayDevice.cs | 45 +++++-- .../Hardware/Gpu/IntelGpuGroup.cs | 90 +++++++++++++ .../Hardware/Gpu/IntelIntegratedGpu.cs | 120 ++++++++++++++++++ .../Hardware/HardwareType.cs | 1 + 9 files changed, 276 insertions(+), 11 deletions(-) create mode 100644 LibreHardwareMonitor/Resources/intel.png create mode 100644 LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs diff --git a/LibreHardwareMonitor/Resources/intel.png b/LibreHardwareMonitor/Resources/intel.png new file mode 100644 index 0000000000000000000000000000000000000000..360f5f57089e85f3fcb3de10aaeb35be890f0cb0 GIT binary patch literal 406 zcmV;H0crk;P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0V_#FK~y+TV`L~g z$v_HVg3?3-I%r^45o6@%gz~^ZUXWd1iVMnt0bgx_Xk%d@gNcEQje&(3A_@V1Is#=* zl28r|7)Wtj%JTpjEJeb94}WBcbx^qW;=7e1&*Z}|fug3e+>R=I@4x@ax0QJJ?N95T zXJB0*z!ab(s4mKpWhExb$NJ*a?V#??=ur4!@O`sh-x4}c)EV) z)4qc*J=aQY=i2OlO~beg66PzT2OG{GWgR@4xeD(); + RemoveType(); } _cpuEnabled = value; @@ -166,11 +168,13 @@ namespace LibreHardwareMonitor.Hardware { Add(new AmdGpuGroup(_settings)); Add(new NvidiaGroup(_settings)); + Add(new IntelGpuGroup(GetIntelCpus(), _settings)); } else { RemoveType(); RemoveType(); + RemoveType(); } } @@ -497,7 +501,7 @@ namespace LibreHardwareMonitor.Hardware Add(new MotherboardGroup(_smbios, _settings)); if (_cpuEnabled) - Add(new CPU.CpuGroup(_settings)); + Add(new CpuGroup(_settings)); if (_memoryEnabled) Add(new MemoryGroup(_settings)); @@ -506,6 +510,7 @@ namespace LibreHardwareMonitor.Hardware { Add(new AmdGpuGroup(_settings)); Add(new NvidiaGroup(_settings)); + Add(new IntelGpuGroup(GetIntelCpus(), _settings)); } if (_controllerEnabled) @@ -653,6 +658,16 @@ namespace LibreHardwareMonitor.Hardware } } + private List GetIntelCpus() + { + // Create a temporary cpu group if one has not been added. + lock (_lock) + { + IGroup cpuGroup = _groups.Find(x => x is CpuGroup) ?? new CpuGroup(_settings); + return cpuGroup.Hardware.Select(x => x as IntelCpu).ToList(); + } + } + /// /// specific additional settings passed to its . /// diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs index d749bef..6122956 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs @@ -30,6 +30,8 @@ namespace LibreHardwareMonitor.Hardware.CPU private readonly Sensor[] _powerSensors; private readonly double _timeStampCounterMultiplier; + public float EnergyUnitsMultiplier => _energyUnitMultiplier; + public IntelCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) { // set tjMax @@ -401,6 +403,9 @@ namespace LibreHardwareMonitor.Hardware.CPU if (!Ring0.ReadMsr(_energyStatusMsrs[i], out eax, out uint _)) continue; + // Don't show the "GPU Graphics" sensor on windows, it will show up under the GPU instead. + if (i == 2 && !Software.OperatingSystem.IsUnix) + continue; _lastEnergyTime[i] = DateTime.UtcNow; _lastEnergyConsumed[i] = eax; diff --git a/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs index bc2a2cc..a7e1130 100644 --- a/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs +++ b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs @@ -66,6 +66,7 @@ namespace LibreHardwareMonitor.Hardware if (!adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.SoftwareDevice)) return false; + deviceInfo.Integrated = !adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.HybridIntegrated); GetQueryStatisticsAdapterInformation(out status, adapter, out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation); if (status != WinNt.STATUS_SUCCESS) @@ -93,13 +94,20 @@ namespace LibreHardwareMonitor.Hardware deviceInfo.Nodes[nodeId] = new D3DDeviceNodeInfo { - Id = nodeId, - Name = GetNodeEngineTypeString(nodeMetaData), - RunningTime = nodeInformation.GlobalInformation.RunningTime.QuadPart, + Id = nodeId, + Name = GetNodeEngineTypeString(nodeMetaData), + RunningTime = nodeInformation.GlobalInformation.RunningTime.QuadPart, QueryTime = queryTime }; } + GetSegmentSize(out status, adapter, out D3dkmth.D3DKMT_SEGMENTSIZEINFO segmentSizeInfo); + if (status != WinNt.STATUS_SUCCESS) + return false; + + deviceInfo.GpuSharedLimit = segmentSizeInfo.SharedSystemMemorySize; + deviceInfo.GpuDedicatedLimit = segmentSizeInfo.DedicatedSystemMemorySize; + for (uint segmentId = 0; segmentId < segmentCount; segmentId++) { GetQueryStatisticsSegment(out status, adapter, segmentId, out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation); @@ -107,7 +115,6 @@ namespace LibreHardwareMonitor.Hardware return false; - ulong commitLimit = segmentInformation.CommitLimit; ulong bytesResident = segmentInformation.BytesResident; ulong bytesCommitted = segmentInformation.BytesCommitted; @@ -115,13 +122,11 @@ namespace LibreHardwareMonitor.Hardware if (aperture == 1) { - deviceInfo.GpuSharedLimit += commitLimit; deviceInfo.GpuSharedUsed += bytesResident; deviceInfo.GpuSharedMax += bytesCommitted; } else { - deviceInfo.GpuDedicatedLimit += commitLimit; deviceInfo.GpuDedicatedUsed += bytesResident; deviceInfo.GpuDedicatedMax += bytesCommitted; } @@ -135,7 +140,7 @@ namespace LibreHardwareMonitor.Hardware { return nodeMetaData.NodeData.EngineType switch { - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OTHER => "D3D " + nodeMetaData.NodeData.FriendlyName, + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OTHER => "D3D " + (!string.IsNullOrWhiteSpace(nodeMetaData.NodeData.FriendlyName) ? nodeMetaData.NodeData.FriendlyName : "Other"), 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", @@ -148,6 +153,29 @@ namespace LibreHardwareMonitor.Hardware }; } + private static void GetSegmentSize + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + out D3dkmth.D3DKMT_SEGMENTSIZEINFO sizeInformation) + { + IntPtr segmentSizePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO))); + sizeInformation = new D3dkmth.D3DKMT_SEGMENTSIZEINFO(); + Marshal.StructureToPtr(sizeInformation, segmentSizePtr, true); + + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO + { + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_GETSEGMENTSIZE, + pPrivateDriverData = segmentSizePtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO)) + }; + + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + sizeInformation = Marshal.PtrToStructure(segmentSizePtr); + Marshal.FreeHGlobal(segmentSizePtr); + } + 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))); @@ -261,6 +289,7 @@ namespace LibreHardwareMonitor.Hardware public ulong GpuDedicatedMax; public D3DDeviceNodeInfo[] Nodes; - } + public bool Integrated; +} } } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs new file mode 100644 index 0000000..431c501 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs @@ -0,0 +1,90 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) LibreHardwareMonitor and Contributors. +// All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using LibreHardwareMonitor.Hardware.CPU; + +namespace LibreHardwareMonitor.Hardware.Gpu +{ + internal class IntelGpuGroup : IGroup + { + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public IntelGpuGroup(List intelCpus, ISettings settings) + { + if (!Software.OperatingSystem.IsUnix && intelCpus?.Count > 0) + { + _report.AppendLine("Intel GPU (D3D)"); + _report.AppendLine(); + + string[] ids = D3DDisplayDevice.GetDeviceIdentifiers(); + + _report.Append("Number of adapters: "); + _report.AppendLine(ids.Length.ToString(CultureInfo.InvariantCulture)); + _report.AppendLine(); + + for (int i = 0; i < ids.Length; i++) + { + string deviceId = ids[i]; + bool isIntel = deviceId.IndexOf("VEN_8086", StringComparison.Ordinal) != -1; + + _report.Append("AdapterIndex: "); + _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); + _report.Append("DeviceId: "); + _report.AppendLine(deviceId); + _report.Append("IsIntel: "); + _report.AppendLine(isIntel.ToString(CultureInfo.InvariantCulture)); + + if (isIntel) + { + if (D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _report.Append("GpuSharedLimit: "); + _report.AppendLine(deviceInfo.GpuSharedLimit.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuSharedUsed: "); + _report.AppendLine(deviceInfo.GpuSharedUsed.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuSharedMax: "); + _report.AppendLine(deviceInfo.GpuSharedMax.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedLimit: "); + _report.AppendLine(deviceInfo.GpuDedicatedLimit.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedUsed: "); + _report.AppendLine(deviceInfo.GpuDedicatedUsed.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedMax: "); + _report.AppendLine(deviceInfo.GpuDedicatedMax.ToString(CultureInfo.InvariantCulture)); + _report.Append("Integrated: "); + _report.AppendLine(deviceInfo.Integrated.ToString(CultureInfo.InvariantCulture)); + + if (deviceInfo.Integrated) + { + // It may seem strange to only use the first cpu here, but in-case we have a multi cpu system with integrated graphics (does that exist?), + // we would pick up the multiple device identifiers above and would add one instance for each CPU. + _hardware.Add(new IntelIntegratedGpu(intelCpus[0], deviceId, deviceInfo, settings)); + } + } + } + + _report.AppendLine(); + } + } + } + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + return _report.ToString(); + } + + public void Close() + { + foreach (Hardware gpu in _hardware) + gpu.Close(); + } + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs new file mode 100644 index 0000000..a7f4e0c --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs @@ -0,0 +1,120 @@ +using Microsoft.Win32; +using System; +using System.Globalization; +using System.Linq; + +namespace LibreHardwareMonitor.Hardware.Gpu +{ + internal class IntelIntegratedGpu : Hardware + { + private readonly string _deviceId; + private readonly Sensor _dedicatedMemoryUsage; + private readonly D3DDisplayDevice.D3DDeviceInfo _deviceInfo; + private readonly float _energyUnitMultiplier; + private readonly CPU.IntelCpu _intelCpu; + private uint _lastEnergyConsumed; + private DateTime _lastEnergyTime; + private const uint MSR_RAPL_POWER_UNIT = 0x606; + private const uint MSR_PP1_ENERGY_STATUS = 0x641; + private readonly Sensor[] _nodeUsage; + private readonly DateTime[] _nodeUsagePrevTick; + private readonly long[] _nodeUsagePrevValue; + private readonly Sensor _powerSensor; + private readonly Sensor _sharedMemoryUsage; + + public override HardwareType HardwareType => HardwareType.GpuIntel; + + public IntelIntegratedGpu(CPU.IntelCpu intelCpu, string deviceId, D3DDisplayDevice.D3DDeviceInfo deviceInfo, ISettings settings) + : base(GetName(deviceId), + new Identifier("gpu-intel-integrated", deviceId.ToString(CultureInfo.InvariantCulture)), + settings) + { + _intelCpu = intelCpu; + _deviceId = deviceId; + _deviceInfo = deviceInfo; + + var memorySensorIndex = 0; + + if (_deviceInfo.GpuDedicatedLimit > 0) + { + _dedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + } + _sharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + + if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out var eax, out var _)) + { + _energyUnitMultiplier = _intelCpu.EnergyUnitsMultiplier; + if (_energyUnitMultiplier != 0) + { + _lastEnergyTime = DateTime.UtcNow; + _lastEnergyConsumed = eax; + _powerSensor = new Sensor("GPU Power", 0, SensorType.Power, this, settings); + ActivateSensor(_powerSensor); + } + } + + _nodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _nodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _nodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; + + var nodeSensorIndex = 0; + foreach(var node in deviceInfo.Nodes.OrderBy(x => x.Name)) + { + _nodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); + _nodeUsagePrevValue[node.Id] = node.RunningTime; + _nodeUsagePrevTick[node.Id] = node.QueryTime; + } + } + + public override void Update() + { + if (D3DDisplayDevice.GetDeviceInfoByIdentifier(_deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + if (_dedicatedMemoryUsage != null) + { + _dedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + ActivateSensor(_dedicatedMemoryUsage); + } + + _sharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_sharedMemoryUsage); + + if (_powerSensor != null && Ring0.ReadMsr(MSR_PP1_ENERGY_STATUS, out var eax, out var _)) + { + var time = DateTime.UtcNow; + uint energyConsumed = eax; + float deltaTime = (float)(time - _lastEnergyTime).TotalSeconds; + if (deltaTime >= 0.01) + { + _powerSensor.Value = _energyUnitMultiplier * unchecked(energyConsumed - _lastEnergyConsumed) / deltaTime; + _lastEnergyTime = time; + _lastEnergyConsumed = energyConsumed; + } + } + + foreach (var node in deviceInfo.Nodes) + { + long runningTimeDiff = node.RunningTime - _nodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _nodeUsagePrevTick[node.Id].Ticks; + + _nodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _nodeUsagePrevValue[node.Id] = node.RunningTime; + _nodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_nodeUsage[node.Id]); + } + } + } + + private static string GetName(string deviceId) + { + var path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); + + if (Registry.GetValue(path, "DeviceDesc", null) is string deviceDesc) + { + return deviceDesc.Split(';').Last(); + } + + return "Intel Integrated Graphics"; + } + } +} diff --git a/LibreHardwareMonitorLib/Hardware/HardwareType.cs b/LibreHardwareMonitorLib/Hardware/HardwareType.cs index 689a5e2..97742d0 100644 --- a/LibreHardwareMonitorLib/Hardware/HardwareType.cs +++ b/LibreHardwareMonitorLib/Hardware/HardwareType.cs @@ -17,6 +17,7 @@ namespace LibreHardwareMonitor.Hardware Memory, GpuNvidia, GpuAmd, + GpuIntel, Storage, Network, Cooler,