Skip to content

Commit de92267

Browse files
committed
Add VRAM memory and bandwidth sensors for Intel discrete GPUs
- Add GPU Memory Total, Used, Free sensors (SmallData type, in MB) - Add GPU Memory load sensor (percentage) - Add GPU Memory Read/Write bandwidth sensors (Throughput type, in B/s) - Use D3DDisplayDevice API to query VRAM usage via Windows kernel - Match Intel discrete GPUs using PCI vendor/device IDs - Include fallback detection for Intel GPUs if initial matching fails - Bandwidth sensors read from Intel GCL telemetry with unit conversion
1 parent cb4d25f commit de92267

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

OpenHardwareMonitorLib/Hardware/Gpu/IntelDiscreteGpu.cs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,20 @@ internal sealed class IntelDiscreteGpu : GenericGpu
3333
private readonly Sensor _voltageCore;
3434
private readonly Sensor _voltageMemory;
3535

36+
// Memory sensors
37+
private readonly Sensor _memoryFree;
38+
private readonly Sensor _memoryTotal;
39+
private readonly Sensor _memoryUsed;
40+
private readonly Sensor _memoryLoad;
41+
42+
// Bandwidth sensors
43+
private readonly Sensor _memoryBandwidthRead;
44+
private readonly Sensor _memoryBandwidthWrite;
45+
3646
// Timestamps
3747
private double _currentTimestamp = double.NaN;
3848
private string _deviceId;
49+
private string _d3dDeviceId;
3950

4051
// Intel GCL properties and data
4152
private readonly IntelGcl.ctl_device_adapter_handle_t _handle;
@@ -49,6 +60,8 @@ internal sealed class IntelDiscreteGpu : GenericGpu
4960
private double _lastRenderComputeActivityCounter = double.NaN;
5061
private double _lastTimestamp = double.NaN;
5162
private double _lastTotalCardEnergyReading = double.NaN;
63+
private double _lastVramReadBandwidthCounter = double.NaN;
64+
private double _lastVramWriteBandwidthCounter = double.NaN;
5265
private IntelGcl.ctl_device_adapter_properties_t _properties;
5366

5467
// Telemetry data
@@ -64,6 +77,9 @@ public IntelDiscreteGpu(IntelGcl.ctl_device_adapter_handle_t handle, ISettings s
6477
if (!InitializeDevice())
6578
return;
6679

80+
// Try to get D3D device identifier for memory monitoring
81+
_d3dDeviceId = GetD3DDeviceId();
82+
6783
// Initialize temperature sensors
6884
_temperatureGpuCore = new Sensor("GPU Core", 0, SensorType.Temperature, this, settings);
6985
_temperatureMemory = new Sensor("GPU Memory", 1, SensorType.Temperature, this, settings);
@@ -85,6 +101,16 @@ public IntelDiscreteGpu(IntelGcl.ctl_device_adapter_handle_t handle, ISettings s
85101
_loadRenderCompute = new Sensor("GPU Render/Compute", 1, SensorType.Load, this, settings);
86102
_loadMedia = new Sensor("GPU Media", 2, SensorType.Load, this, settings);
87103

104+
// Initialize memory sensors
105+
_memoryFree = new Sensor("GPU Memory Free", 0, SensorType.SmallData, this, settings);
106+
_memoryUsed = new Sensor("GPU Memory Used", 1, SensorType.SmallData, this, settings);
107+
_memoryTotal = new Sensor("GPU Memory Total", 2, SensorType.SmallData, this, settings);
108+
_memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
109+
110+
// Initialize bandwidth sensors
111+
_memoryBandwidthRead = new Sensor("GPU Memory Read", 0, SensorType.Throughput, this, settings);
112+
_memoryBandwidthWrite = new Sensor("GPU Memory Write", 1, SensorType.Throughput, this, settings);
113+
88114
// Initialize fan sensors based on available fans
89115
int fanCount = (int)GetFanCount();
90116
_fans = new Sensor[fanCount];
@@ -159,6 +185,34 @@ private bool InitializeDevice()
159185
return false;
160186
}
161187

188+
private string GetD3DDeviceId()
189+
{
190+
// Try to find matching D3D device using PCI device ID
191+
string[] deviceIdentifiers = D3DDisplayDevice.GetDeviceIdentifiers();
192+
if (deviceIdentifiers == null || deviceIdentifiers.Length == 0)
193+
return null;
194+
195+
// Intel vendor ID is 0x8086
196+
string vendorPattern = $"VEN_{_properties.pci_vendor_id:X}";
197+
string devicePattern = $"DEV_{_properties.pci_device_id:X}";
198+
199+
foreach (string deviceIdentifier in deviceIdentifiers)
200+
{
201+
// Check if this device matches Intel vendor and device IDs
202+
if (deviceIdentifier.IndexOf(vendorPattern, StringComparison.OrdinalIgnoreCase) != -1 &&
203+
deviceIdentifier.IndexOf(devicePattern, StringComparison.OrdinalIgnoreCase) != -1)
204+
{
205+
// Verify it's a valid D3D device by trying to get device info
206+
if (D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceIdentifier, out D3DDisplayDevice.D3DDeviceInfo deviceInfo))
207+
{
208+
return deviceIdentifier;
209+
}
210+
}
211+
}
212+
213+
return null;
214+
}
215+
162216
public override void Update()
163217
{
164218
if (!IsValid)
@@ -191,6 +245,19 @@ public override void Update()
191245
UpdateUtilizationFromActivityCounter(_telemetry.renderComputeActivityCounter, ref _lastRenderComputeActivityCounter, _loadRenderCompute);
192246
UpdateUtilizationFromActivityCounter(_telemetry.mediaActivityCounter, ref _lastMediaActivityCounter, _loadMedia);
193247

248+
// Try to get D3D device ID if we haven't found it yet
249+
if (string.IsNullOrEmpty(_d3dDeviceId))
250+
{
251+
_d3dDeviceId = GetD3DDeviceId();
252+
}
253+
254+
// Update VRAM memory sensors (using D3D API)
255+
UpdateMemorySensors();
256+
257+
// Update VRAM bandwidth sensors
258+
UpdateBandwidthFromCounter(_telemetry.vramReadBandwidth, ref _lastVramReadBandwidthCounter, _memoryBandwidthRead);
259+
UpdateBandwidthFromCounter(_telemetry.vramWriteBandwidth, ref _lastVramWriteBandwidthCounter, _memoryBandwidthWrite);
260+
194261
// Update fan sensors
195262
UpdateFanSpeeds(_fans);
196263
}
@@ -420,4 +487,97 @@ private void UpdateUtilizationFromActivityCounter(IntelGcl.ctl_oc_telemetry_item
420487

421488
lastActivityReading = currentActivity;
422489
}
490+
491+
private void UpdateMemorySensors()
492+
{
493+
if (string.IsNullOrEmpty(_d3dDeviceId))
494+
{
495+
// Fallback: Try to find any Intel discrete GPU
496+
string[] deviceIdentifiers = D3DDisplayDevice.GetDeviceIdentifiers();
497+
if (deviceIdentifiers != null)
498+
{
499+
foreach (string deviceId in deviceIdentifiers)
500+
{
501+
if (deviceId.IndexOf("VEN_8086", StringComparison.OrdinalIgnoreCase) != -1)
502+
{
503+
if (D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo testInfo))
504+
{
505+
if (testInfo.GpuDedicatedLimit > 0 && !testInfo.Integrated)
506+
{
507+
_d3dDeviceId = deviceId;
508+
break;
509+
}
510+
}
511+
}
512+
}
513+
}
514+
515+
if (string.IsNullOrEmpty(_d3dDeviceId))
516+
return;
517+
}
518+
519+
if (D3DDisplayDevice.GetDeviceInfoByIdentifier(_d3dDeviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo))
520+
{
521+
// Get dedicated video memory (VRAM) usage
522+
ulong totalBytes = deviceInfo.GpuDedicatedLimit;
523+
ulong usedBytes = deviceInfo.GpuDedicatedUsed;
524+
ulong freeBytes = totalBytes > usedBytes ? totalBytes - usedBytes : 0;
525+
526+
if (totalBytes > 0)
527+
{
528+
// Convert bytes to MB for display
529+
_memoryTotal.Value = totalBytes / (1024.0f * 1024.0f);
530+
ActivateSensor(_memoryTotal);
531+
532+
_memoryUsed.Value = usedBytes / (1024.0f * 1024.0f);
533+
ActivateSensor(_memoryUsed);
534+
535+
_memoryFree.Value = freeBytes / (1024.0f * 1024.0f);
536+
ActivateSensor(_memoryFree);
537+
538+
// Calculate load percentage
539+
_memoryLoad.Value = (float)((double)usedBytes / totalBytes * 100.0);
540+
ActivateSensor(_memoryLoad);
541+
}
542+
}
543+
}
544+
545+
private void UpdateBandwidthFromCounter(IntelGcl.ctl_oc_telemetry_item_t bandwidthItem, ref double lastBandwidthReading, Sensor bandwidthSensor)
546+
{
547+
if (!IsValid || bandwidthSensor == null)
548+
return;
549+
550+
// If the telemetry item directly provides bandwidth value (not a counter)
551+
if (bandwidthItem.bSupported)
552+
{
553+
double bandwidthValue = GetTelemetryValue(bandwidthItem);
554+
555+
if (!double.IsNaN(bandwidthValue) && bandwidthValue >= 0)
556+
{
557+
// Bandwidth is typically in GB/s or MB/s, convert to B/s for Throughput sensor
558+
// Check the units to determine if conversion is needed
559+
if (bandwidthItem.units == IntelGcl.ctl_units_t.CTL_UNITS_BANDWIDTH_MBPS)
560+
{
561+
// Convert MB/s to B/s (multiply by 1024*1024)
562+
bandwidthValue = bandwidthValue * 1024.0 * 1024.0;
563+
}
564+
else if (bandwidthItem.units == IntelGcl.ctl_units_t.CTL_UNITS_MEM_SPEED_GBPS)
565+
{
566+
// Convert GB/s to B/s (multiply by 1024*1024*1024)
567+
bandwidthValue = bandwidthValue * 1024.0 * 1024.0 * 1024.0;
568+
}
569+
570+
bandwidthSensor.Value = (float)bandwidthValue;
571+
ActivateSensor(bandwidthSensor);
572+
}
573+
else
574+
{
575+
bandwidthSensor.Value = null;
576+
}
577+
}
578+
else
579+
{
580+
bandwidthSensor.Value = null;
581+
}
582+
}
423583
}

0 commit comments

Comments
 (0)