Intel discrete GPU support (#1822)
* Intel discrete GPU support through Intel GCL library * Formatting --------- Co-authored-by: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com>
This commit is contained in:
co-authored by
PhyxionNL
parent
8b42be793b
commit
fe9857c2ed
@@ -0,0 +1,428 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
using LibreHardwareMonitor.Interop;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Gpu;
|
||||
|
||||
internal sealed class IntelDiscreteGpu : GenericGpu
|
||||
{
|
||||
// Constants
|
||||
private const double MemoryFrequencyDivisor = 8.0; // Intel GCL returns memory frequency multiplied by 8
|
||||
|
||||
// Clock sensors
|
||||
private readonly Sensor _clockCore;
|
||||
private readonly Sensor _clockMemory;
|
||||
|
||||
// Fan sensors
|
||||
private readonly Sensor[] _fans;
|
||||
|
||||
// Utilization sensors
|
||||
private readonly Sensor _loadGlobalActivity;
|
||||
private readonly Sensor _loadMedia;
|
||||
private readonly Sensor _loadRenderCompute;
|
||||
|
||||
// Power sensors
|
||||
private readonly Sensor _powerGpu;
|
||||
private readonly Sensor _powerTotal;
|
||||
|
||||
// Temperature sensors
|
||||
private readonly Sensor _temperatureGpuCore;
|
||||
private readonly Sensor _temperatureMemory;
|
||||
|
||||
// Voltage sensors
|
||||
private readonly Sensor _voltageCore;
|
||||
private readonly Sensor _voltageMemory;
|
||||
|
||||
// Timestamps
|
||||
private double _currentTimestamp = double.NaN;
|
||||
private string _deviceId;
|
||||
|
||||
// Intel GCL properties and data
|
||||
private readonly IntelGcl.ctl_device_adapter_handle_t _handle;
|
||||
|
||||
// Power calculation support
|
||||
private double _lastEnergyReading = double.NaN;
|
||||
|
||||
// Activity counter calculation support
|
||||
private double _lastGlobalActivityCounter = double.NaN;
|
||||
private double _lastMediaActivityCounter = double.NaN;
|
||||
private double _lastRenderComputeActivityCounter = double.NaN;
|
||||
private double _lastTimestamp = double.NaN;
|
||||
private double _lastTotalCardEnergyReading = double.NaN;
|
||||
private IntelGcl.ctl_device_adapter_properties_t _properties;
|
||||
|
||||
// Telemetry data
|
||||
private IntelGcl.ctl_power_telemetry_t _telemetry;
|
||||
|
||||
public IntelDiscreteGpu(IntelGcl.ctl_device_adapter_handle_t handle, ISettings settings)
|
||||
: base(GetDeviceName(handle), new Identifier("gpu-intel", GetDeviceId(handle)), settings)
|
||||
{
|
||||
_handle = handle;
|
||||
IsValid = false;
|
||||
|
||||
// Initialize device properties
|
||||
if (!InitializeDevice())
|
||||
return;
|
||||
|
||||
// Initialize temperature sensors
|
||||
_temperatureGpuCore = new Sensor("GPU Core", 0, SensorType.Temperature, this, settings);
|
||||
_temperatureMemory = new Sensor("GPU Memory", 1, SensorType.Temperature, this, settings);
|
||||
|
||||
// Initialize clock sensors
|
||||
_clockCore = new Sensor("GPU Core", 0, SensorType.Clock, this, settings);
|
||||
_clockMemory = new Sensor("GPU Memory", 1, SensorType.Clock, this, settings);
|
||||
|
||||
// Initialize voltage sensors
|
||||
_voltageCore = new Sensor("GPU Core", 0, SensorType.Voltage, this, settings);
|
||||
_voltageMemory = new Sensor("GPU Memory", 1, SensorType.Voltage, this, settings);
|
||||
|
||||
// Initialize power sensors
|
||||
_powerGpu = new Sensor("GPU Package", 0, SensorType.Power, this, settings);
|
||||
_powerTotal = new Sensor("GPU Total", 1, SensorType.Power, this, settings);
|
||||
|
||||
// Initialize utilization sensors
|
||||
_loadGlobalActivity = new Sensor("GPU Core", 0, SensorType.Load, this, settings);
|
||||
_loadRenderCompute = new Sensor("GPU Render/Compute", 1, SensorType.Load, this, settings);
|
||||
_loadMedia = new Sensor("GPU Media", 2, SensorType.Load, this, settings);
|
||||
|
||||
// Initialize fan sensors based on available fans
|
||||
int fanCount = (int)GetFanCount();
|
||||
_fans = new Sensor[fanCount];
|
||||
|
||||
for (int i = 0; i < fanCount; i++)
|
||||
{
|
||||
string fanName = fanCount == 1 ? "GPU Fan" : $"GPU Fan {i + 1}";
|
||||
_fans[i] = new Sensor(fanName, i, SensorType.Fan, this, settings);
|
||||
}
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public override string DeviceId => _deviceId ?? GetDeviceId(_handle);
|
||||
|
||||
public uint DriverVersion { get; private set; }
|
||||
|
||||
public override HardwareType HardwareType => HardwareType.GpuIntel;
|
||||
|
||||
public bool IsValid { get; private set; }
|
||||
|
||||
public uint RevisionId { get; private set; }
|
||||
|
||||
public uint VendorId { get; private set; }
|
||||
|
||||
private static bool TryGetDeviceProperties(IntelGcl.ctl_device_adapter_handle_t handle, out IntelGcl.ctl_device_adapter_properties_t properties)
|
||||
{
|
||||
properties = new IntelGcl.ctl_device_adapter_properties_t
|
||||
{
|
||||
Size = (uint)Marshal.SizeOf(typeof(IntelGcl.ctl_device_adapter_properties_t)),
|
||||
Version = 2
|
||||
};
|
||||
|
||||
int result = IntelGcl.ctlGetDeviceProperties(handle, ref properties);
|
||||
return result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS &&
|
||||
properties.device_type == IntelGcl.ctl_device_type_t.CTL_DEVICE_TYPE_GRAPHICS;
|
||||
}
|
||||
|
||||
private static string GetDeviceName(IntelGcl.ctl_device_adapter_handle_t handle)
|
||||
{
|
||||
if (TryGetDeviceProperties(handle, out IntelGcl.ctl_device_adapter_properties_t properties))
|
||||
{
|
||||
return properties.name;
|
||||
}
|
||||
|
||||
return "Intel GPU";
|
||||
}
|
||||
|
||||
private static string GetDeviceId(IntelGcl.ctl_device_adapter_handle_t handle)
|
||||
{
|
||||
if (TryGetDeviceProperties(handle, out IntelGcl.ctl_device_adapter_properties_t properties))
|
||||
{
|
||||
return $"0x{properties.pci_device_id:X4}";
|
||||
}
|
||||
|
||||
return "0x0000";
|
||||
}
|
||||
|
||||
// Device initialization
|
||||
private bool InitializeDevice()
|
||||
{
|
||||
if (TryGetDeviceProperties(_handle, out _properties))
|
||||
{
|
||||
_deviceId = $"0x{_properties.pci_device_id:X4}";
|
||||
VendorId = _properties.pci_vendor_id;
|
||||
RevisionId = _properties.rev_id;
|
||||
DriverVersion = (uint)_properties.driver_version;
|
||||
IsValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (!IsValid)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Update telemetry data from Intel GCL
|
||||
if (!UpdateTelemetry())
|
||||
return;
|
||||
|
||||
// Update power sensors
|
||||
UpdatePowerFromEnergyCounter(_telemetry.gpuEnergyCounter, ref _lastEnergyReading, _powerGpu);
|
||||
UpdatePowerFromEnergyCounter(_telemetry.totalCardEnergyCounter, ref _lastTotalCardEnergyReading, _powerTotal);
|
||||
|
||||
// Update temperature sensors
|
||||
UpdateSensorFromTelemetry(_telemetry.gpuCurrentTemperature, _temperatureGpuCore);
|
||||
UpdateSensorFromTelemetry(_telemetry.vramCurrentTemperature, _temperatureMemory);
|
||||
|
||||
// Update clock sensors
|
||||
UpdateSensorFromTelemetry(_telemetry.gpuCurrentClockFrequency, _clockCore);
|
||||
UpdateMemoryFrequency(_clockMemory);
|
||||
|
||||
// Update voltage sensors
|
||||
UpdateSensorFromTelemetry(_telemetry.gpuVoltage, _voltageCore);
|
||||
UpdateSensorFromTelemetry(_telemetry.vramVoltage, _voltageMemory);
|
||||
|
||||
// Update utilization sensors
|
||||
UpdateUtilizationFromActivityCounter(_telemetry.globalActivityCounter, ref _lastGlobalActivityCounter, _loadGlobalActivity);
|
||||
UpdateUtilizationFromActivityCounter(_telemetry.renderComputeActivityCounter, ref _lastRenderComputeActivityCounter, _loadRenderCompute);
|
||||
UpdateUtilizationFromActivityCounter(_telemetry.mediaActivityCounter, ref _lastMediaActivityCounter, _loadMedia);
|
||||
|
||||
// Update fan sensors
|
||||
UpdateFanSpeeds(_fans);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log error but don't crash the update
|
||||
System.Diagnostics.Debug.WriteLine($"Error updating Intel GPU sensors: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpdateTelemetry()
|
||||
{
|
||||
if (!IsValid)
|
||||
return false;
|
||||
|
||||
var telemetry = new IntelGcl.ctl_power_telemetry_t
|
||||
{
|
||||
Size = (uint)Marshal.SizeOf(typeof(IntelGcl.ctl_power_telemetry_t)),
|
||||
Version = 1,
|
||||
psu = new IntelGcl.ctl_psu_info_t[IntelGcl.CTL_PSU_COUNT],
|
||||
fanSpeed = new IntelGcl.ctl_oc_telemetry_item_t[IntelGcl.CTL_FAN_COUNT]
|
||||
};
|
||||
|
||||
if (IntelGcl.ctlPowerTelemetryGet(_handle, ref telemetry) == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
{
|
||||
_telemetry = telemetry;
|
||||
_lastTimestamp = _currentTimestamp;
|
||||
_currentTimestamp = _telemetry.timeStamp.bSupported ? GetTelemetryValue(_telemetry.timeStamp) : DateTimeOffset.UtcNow.Ticks;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateMemoryFrequency(Sensor sensor)
|
||||
{
|
||||
double frequency = double.NaN;
|
||||
|
||||
uint freqCount = 0;
|
||||
int result = IntelGcl.ctlEnumFrequencyDomains(_handle, ref freqCount, null);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS && freqCount > 0)
|
||||
{
|
||||
var freqHandles = new IntelGcl.ctl_freq_handle_t[freqCount];
|
||||
result = IntelGcl.ctlEnumFrequencyDomains(_handle, ref freqCount, freqHandles);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
{
|
||||
for (int i = 0; i < freqCount; i++)
|
||||
{
|
||||
var properties = new IntelGcl.ctl_freq_properties_t
|
||||
{
|
||||
Size = (uint)Marshal.SizeOf(typeof(IntelGcl.ctl_freq_properties_t)),
|
||||
Version = 0
|
||||
};
|
||||
|
||||
result = IntelGcl.ctlFrequencyGetProperties(freqHandles[i], ref properties);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS &&
|
||||
properties.type == IntelGcl.ctl_freq_domain_t.CTL_FREQ_DOMAIN_MEMORY)
|
||||
{
|
||||
var state = new IntelGcl.ctl_freq_state_t
|
||||
{
|
||||
Size = (uint)Marshal.SizeOf(typeof(IntelGcl.ctl_freq_state_t)),
|
||||
Version = 0
|
||||
};
|
||||
|
||||
result = IntelGcl.ctlFrequencyGetState(freqHandles[i], ref state);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS && state.actual >= 0)
|
||||
{
|
||||
frequency = state.actual / MemoryFrequencyDivisor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (double.IsNaN(frequency) && _telemetry.vramCurrentClockFrequency.bSupported)
|
||||
{
|
||||
frequency = GetTelemetryValue(_telemetry.vramCurrentClockFrequency);
|
||||
}
|
||||
|
||||
if (!double.IsNaN(frequency))
|
||||
{
|
||||
sensor.Value = (float)frequency;
|
||||
ActivateSensor(sensor);
|
||||
}
|
||||
else
|
||||
{
|
||||
sensor.Value = null;
|
||||
}
|
||||
}
|
||||
|
||||
private uint GetFanCount()
|
||||
{
|
||||
uint fanCount = 0;
|
||||
int result = IntelGcl.ctlEnumFans(_handle, ref fanCount, null);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
{
|
||||
return fanCount;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void UpdateFanSpeeds(Sensor[] fanSensors)
|
||||
{
|
||||
uint fanCount = (uint)Math.Min(Math.Max(0, GetFanCount()), fanSensors.Length);
|
||||
if (fanCount == 0)
|
||||
return;
|
||||
|
||||
var fanHandles = new IntelGcl.ctl_fan_handle_t[fanCount];
|
||||
int result = IntelGcl.ctlEnumFans(_handle, ref fanCount, fanHandles);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
{
|
||||
for (int i = 0; i < fanCount; i++)
|
||||
{
|
||||
int fanSpeed = -1;
|
||||
result = IntelGcl.ctlFanGetState(fanHandles[i], IntelGcl.ctl_fan_speed_units_t.CTL_FAN_SPEED_UNITS_RPM, ref fanSpeed);
|
||||
|
||||
if (result == (int)IntelGcl.ctl_result_t.CTL_RESULT_SUCCESS && fanSpeed >= 0)
|
||||
{
|
||||
fanSensors[i].Value = fanSpeed;
|
||||
ActivateSensor(fanSensors[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
fanSensors[i].Value = null;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = (int)fanCount; i < fanSensors.Length; i++)
|
||||
{
|
||||
fanSensors[i].Value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSensorFromTelemetry(IntelGcl.ctl_oc_telemetry_item_t telemetryItem, Sensor sensor)
|
||||
{
|
||||
if (telemetryItem.bSupported)
|
||||
{
|
||||
sensor.Value = (float)GetTelemetryValue(telemetryItem);
|
||||
ActivateSensor(sensor);
|
||||
}
|
||||
else
|
||||
{
|
||||
sensor.Value = null;
|
||||
}
|
||||
}
|
||||
|
||||
private double GetTelemetryValue(IntelGcl.ctl_oc_telemetry_item_t item)
|
||||
{
|
||||
return item.type switch
|
||||
{
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_FLOAT => item.value.datafloat,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_DOUBLE => item.value.datadouble,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_UINT32 => item.value.datau32,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_INT32 => item.value.data32,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_UINT64 => item.value.datau64,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_INT64 => item.value.data64,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_UINT16 => item.value.datau16,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_INT16 => item.value.data16,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_UINT8 => item.value.datau8,
|
||||
IntelGcl.ctl_data_type_t.CTL_DATA_TYPE_INT8 => item.value.data8,
|
||||
_ => double.NaN
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdatePowerFromEnergyCounter(IntelGcl.ctl_oc_telemetry_item_t energyCounter, ref double lastEnergyReading, Sensor powerSensor)
|
||||
{
|
||||
if (!IsValid || powerSensor == null)
|
||||
return;
|
||||
|
||||
double currentEnergy = energyCounter.bSupported ? GetTelemetryValue(energyCounter) : double.NaN;
|
||||
double deltaTime = _currentTimestamp - _lastTimestamp;
|
||||
|
||||
if (deltaTime > 0.0 && !double.IsNaN(currentEnergy) && !double.IsNaN(lastEnergyReading))
|
||||
{
|
||||
double deltaEnergy = currentEnergy - lastEnergyReading;
|
||||
double power = deltaEnergy / deltaTime;
|
||||
power = power < 0 ? 0 : power;
|
||||
|
||||
powerSensor.Value = (float)power;
|
||||
ActivateSensor(powerSensor);
|
||||
}
|
||||
else
|
||||
{
|
||||
powerSensor.Value = null;
|
||||
}
|
||||
|
||||
lastEnergyReading = currentEnergy;
|
||||
}
|
||||
|
||||
private void UpdateUtilizationFromActivityCounter(IntelGcl.ctl_oc_telemetry_item_t activityCounter, ref double lastActivityReading, Sensor activitySensor)
|
||||
{
|
||||
if (!IsValid || activitySensor == null)
|
||||
return;
|
||||
|
||||
double currentActivity = activityCounter.bSupported ? GetTelemetryValue(activityCounter) : double.NaN;
|
||||
double deltaTime = _currentTimestamp - _lastTimestamp;
|
||||
|
||||
if (deltaTime > 0 && !double.IsNaN(currentActivity) && !double.IsNaN(lastActivityReading))
|
||||
{
|
||||
double activeDiff = currentActivity - lastActivityReading;
|
||||
if (activeDiff >= 0)
|
||||
{
|
||||
double activity = (activeDiff / deltaTime) * 100.0;
|
||||
activity = Math.Min(Math.Max(activity, 0.0), 100.0);
|
||||
|
||||
activitySensor.Value = (float)activity;
|
||||
ActivateSensor(activitySensor);
|
||||
}
|
||||
else
|
||||
{
|
||||
activitySensor.Value = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
activitySensor.Value = null;
|
||||
}
|
||||
|
||||
lastActivityReading = currentActivity;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using LibreHardwareMonitor.Hardware.Cpu;
|
||||
using LibreHardwareMonitor.Interop;
|
||||
|
||||
namespace LibreHardwareMonitor.Hardware.Gpu;
|
||||
|
||||
@@ -18,55 +19,126 @@ internal class IntelGpuGroup : IGroup
|
||||
|
||||
public IntelGpuGroup(List<IntelCpu> intelCpus, ISettings settings)
|
||||
{
|
||||
if (!Software.OperatingSystem.IsUnix && intelCpus?.Count > 0)
|
||||
if (!Software.OperatingSystem.IsUnix)
|
||||
{
|
||||
_report.AppendLine("Intel GPU (D3D)");
|
||||
_report.AppendLine();
|
||||
// Initialize Intel GCL for discrete GPUs
|
||||
bool gclInitialized = false;
|
||||
|
||||
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++)
|
||||
try
|
||||
{
|
||||
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 && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo))
|
||||
if (IntelGcl.IsAvailable)
|
||||
{
|
||||
_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));
|
||||
gclInitialized = IntelGcl.Initialize();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_report.Append("Intel GCL initialization failed: ");
|
||||
_report.AppendLine(ex.Message);
|
||||
}
|
||||
|
||||
if (deviceInfo.Integrated)
|
||||
_report.AppendLine("Intel GPU Detection");
|
||||
_report.AppendLine();
|
||||
_report.Append("Intel GCL Initialized: ");
|
||||
_report.AppendLine(gclInitialized.ToString(CultureInfo.InvariantCulture));
|
||||
_report.AppendLine();
|
||||
|
||||
// Enumerate discrete GPUs using Intel GCL
|
||||
if (gclInitialized)
|
||||
{
|
||||
try
|
||||
{
|
||||
var handles = IntelGcl.GetDeviceHandles();
|
||||
_report.Append("Device handles found: ");
|
||||
_report.AppendLine(handles.Length.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
foreach (var handle in handles)
|
||||
{
|
||||
// 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));
|
||||
try
|
||||
{
|
||||
var gpu = new IntelDiscreteGpu(handle, settings);
|
||||
if (gpu.IsValid)
|
||||
{
|
||||
_report.Append("Discrete GPU: ");
|
||||
_report.AppendLine(gpu.Name);
|
||||
_report.Append("Device ID: ");
|
||||
_report.AppendLine(gpu.DeviceId);
|
||||
_report.AppendLine();
|
||||
|
||||
_hardware.Add(gpu);
|
||||
_report.AppendLine("Successfully added discrete GPU to hardware list");
|
||||
}
|
||||
else
|
||||
{
|
||||
_report.AppendLine("Skipped invalid GPU device");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_report.Append("Failed to create IntelDiscreteGpu: ");
|
||||
_report.AppendLine(ex.Message);
|
||||
_report.AppendLine(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_report.Append("Failed to enumerate Intel GPU devices: ");
|
||||
_report.AppendLine(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate integrated GPUs using D3D (existing logic)
|
||||
if (intelCpus?.Count > 0)
|
||||
{
|
||||
_report.AppendLine("Intel GPU (D3D - Integrated)");
|
||||
_report.AppendLine();
|
||||
|
||||
string[] ids = D3DDisplayDevice.GetDeviceIdentifiers();
|
||||
|
||||
_report.Append("Number of D3D 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 && 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,5 +154,18 @@ internal class IntelGpuGroup : IGroup
|
||||
{
|
||||
foreach (Hardware gpu in _hardware)
|
||||
gpu.Close();
|
||||
|
||||
// Shutdown Intel GCL
|
||||
try
|
||||
{
|
||||
if (IntelGcl.IsInitialized)
|
||||
{
|
||||
IntelGcl.Cleanup();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore shutdown errors
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace LibreHardwareMonitor.Interop;
|
||||
|
||||
internal static class IntelGcl
|
||||
{
|
||||
public const int CTL_FAN_COUNT = 5;
|
||||
public const uint CTL_IMPL_MAJOR_VERSION = 1;
|
||||
public const uint CTL_IMPL_MINOR_VERSION = 1;
|
||||
public const uint CTL_IMPL_VERSION = (CTL_IMPL_MAJOR_VERSION << 16) | CTL_IMPL_MINOR_VERSION;
|
||||
public const int CTL_MAX_DEVICE_NAME_LEN = 100;
|
||||
public const int CTL_MAX_RESERVED_SIZE = 112;
|
||||
public const int CTL_PSU_COUNT = 5;
|
||||
public const int MAX_DEVICES = 64;
|
||||
public const int MAX_STRING_LENGTH = 256;
|
||||
|
||||
private const string DllName = "ControlLib.dll";
|
||||
|
||||
static IntelGcl()
|
||||
{
|
||||
IsAvailable = GclMethodExists(nameof(ctlInit)) && GclMethodExists(nameof(ctlEnumerateDevices));
|
||||
}
|
||||
|
||||
public enum ctl_data_type_t
|
||||
{
|
||||
CTL_DATA_TYPE_INT8 = 0,
|
||||
CTL_DATA_TYPE_UINT8 = 1,
|
||||
CTL_DATA_TYPE_INT16 = 2,
|
||||
CTL_DATA_TYPE_UINT16 = 3,
|
||||
CTL_DATA_TYPE_INT32 = 4,
|
||||
CTL_DATA_TYPE_UINT32 = 5,
|
||||
CTL_DATA_TYPE_INT64 = 6,
|
||||
CTL_DATA_TYPE_UINT64 = 7,
|
||||
CTL_DATA_TYPE_FLOAT = 8,
|
||||
CTL_DATA_TYPE_DOUBLE = 9,
|
||||
CTL_DATA_TYPE_STRING_ASCII = 10,
|
||||
CTL_DATA_TYPE_STRING_UTF16 = 11,
|
||||
CTL_DATA_TYPE_STRING_UTF132 = 12,
|
||||
CTL_DATA_TYPE_UNKNOWN = 0x4800FFFF
|
||||
}
|
||||
|
||||
public enum ctl_device_type_t
|
||||
{
|
||||
CTL_DEVICE_TYPE_GRAPHICS = 1,
|
||||
CTL_DEVICE_TYPE_SYSTEM = 2,
|
||||
CTL_DEVICE_TYPE_MAX
|
||||
}
|
||||
|
||||
public enum ctl_fan_speed_mode_t
|
||||
{
|
||||
CTL_FAN_SPEED_MODE_DEFAULT = 0,
|
||||
CTL_FAN_SPEED_MODE_FIXED = 1,
|
||||
CTL_FAN_SPEED_MODE_TABLE = 2,
|
||||
CTL_FAN_SPEED_MODE_MAX
|
||||
}
|
||||
|
||||
public enum ctl_fan_speed_units_t
|
||||
{
|
||||
CTL_FAN_SPEED_UNITS_RPM = 0,
|
||||
CTL_FAN_SPEED_UNITS_PERCENT = 1,
|
||||
CTL_FAN_SPEED_UNITS_MAX
|
||||
}
|
||||
|
||||
public enum ctl_freq_domain_t
|
||||
{
|
||||
CTL_FREQ_DOMAIN_GPU = 0,
|
||||
CTL_FREQ_DOMAIN_MEMORY = 1,
|
||||
CTL_FREQ_DOMAIN_MEDIA = 2,
|
||||
CTL_FREQ_DOMAIN_MAX
|
||||
}
|
||||
|
||||
// Initialization flags
|
||||
public enum ctl_init_flag_t : uint
|
||||
{
|
||||
CTL_INIT_FLAG_USE_LEVEL_ZERO = 1 << 0, // CTL_BIT(0) - Required for telemetry
|
||||
CTL_INIT_FLAG_MAX = 0x80000000
|
||||
}
|
||||
|
||||
public enum ctl_psu_type_t
|
||||
{
|
||||
CTL_PSU_TYPE_PSU_NONE = 0,
|
||||
CTL_PSU_TYPE_PSU_PCIE = 1,
|
||||
CTL_PSU_TYPE_PSU_6PIN = 2,
|
||||
CTL_PSU_TYPE_PSU_8PIN = 3
|
||||
}
|
||||
|
||||
// Enums
|
||||
public enum ctl_result_t
|
||||
{
|
||||
CTL_RESULT_SUCCESS = 0x00000000,
|
||||
CTL_RESULT_SUCCESS_STILL_OPEN_BY_ANOTHER_CALLER = 0x00000001,
|
||||
CTL_RESULT_ERROR_SUCCESS_END = 0x0000FFFF,
|
||||
CTL_RESULT_ERROR_GENERIC_START = 0x40000000,
|
||||
CTL_RESULT_ERROR_NOT_INITIALIZED = 0x40000001,
|
||||
CTL_RESULT_ERROR_ALREADY_INITIALIZED = 0x40000002,
|
||||
CTL_RESULT_ERROR_DEVICE_LOST = 0x40000003,
|
||||
CTL_RESULT_ERROR_OUT_OF_HOST_MEMORY = 0x40000004,
|
||||
CTL_RESULT_ERROR_OUT_OF_DEVICE_MEMORY = 0x40000005,
|
||||
CTL_RESULT_ERROR_INSUFFICIENT_PERMISSIONS = 0x40000006,
|
||||
CTL_RESULT_ERROR_NOT_AVAILABLE = 0x40000007,
|
||||
CTL_RESULT_ERROR_UNINITIALIZED = 0x40000008,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_VERSION = 0x40000009,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_FEATURE = 0x4000000a,
|
||||
CTL_RESULT_ERROR_INVALID_ARGUMENT = 0x4000000b,
|
||||
CTL_RESULT_ERROR_INVALID_API_HANDLE = 0x4000000c,
|
||||
CTL_RESULT_ERROR_INVALID_NULL_HANDLE = 0x4000000d,
|
||||
CTL_RESULT_ERROR_INVALID_NULL_POINTER = 0x4000000e,
|
||||
CTL_RESULT_ERROR_INVALID_SIZE = 0x4000000f,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_SIZE = 0x40000010,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_ALIGNMENT = 0x40000011,
|
||||
CTL_RESULT_ERROR_INVALID_SYNCHRONIZATION_OBJECT = 0x40000012,
|
||||
CTL_RESULT_ERROR_INVALID_ENUMERATION = 0x40000013,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_ENUMERATION = 0x40000014,
|
||||
CTL_RESULT_ERROR_UNSUPPORTED_IMAGE_FORMAT = 0x40000015,
|
||||
CTL_RESULT_ERROR_INVALID_NATIVE_BINARY = 0x40000016,
|
||||
CTL_RESULT_ERROR_INVALID_GLOBAL_NAME = 0x40000017,
|
||||
CTL_RESULT_ERROR_INVALID_KERNEL_NAME = 0x40000018,
|
||||
CTL_RESULT_ERROR_INVALID_FUNCTION_NAME = 0x40000019,
|
||||
CTL_RESULT_ERROR_INVALID_GROUP_SIZE_DIMENSION = 0x4000001a,
|
||||
CTL_RESULT_ERROR_INVALID_GLOBAL_WIDTH_DIMENSION = 0x4000001b,
|
||||
CTL_RESULT_ERROR_INVALID_KERNEL_ARGUMENT_INDEX = 0x4000001c,
|
||||
CTL_RESULT_ERROR_INVALID_KERNEL_ARGUMENT_SIZE = 0x4000001d,
|
||||
CTL_RESULT_ERROR_INVALID_KERNEL_ATTRIBUTE_VALUE = 0x4000001e,
|
||||
CTL_RESULT_ERROR_INVALID_MODULE_UNLINKED = 0x4000001f,
|
||||
CTL_RESULT_ERROR_INVALID_COMMAND_LIST_TYPE = 0x40000020,
|
||||
CTL_RESULT_ERROR_OVERLAPPING_REGIONS = 0x40000021,
|
||||
CTL_RESULT_ERROR_UNKNOWN = 0x4000FFFF
|
||||
}
|
||||
|
||||
public enum ctl_units_t
|
||||
{
|
||||
CTL_UNITS_FREQUENCY_MHZ = 0,
|
||||
CTL_UNITS_OPERATIONS_GTS = 1,
|
||||
CTL_UNITS_OPERATIONS_MTS = 2,
|
||||
CTL_UNITS_VOLTAGE_VOLTS = 3,
|
||||
CTL_UNITS_POWER_WATTS = 4,
|
||||
CTL_UNITS_TEMPERATURE_CELSIUS = 5,
|
||||
CTL_UNITS_ENERGY_JOULES = 6,
|
||||
CTL_UNITS_TIME_SECONDS = 7,
|
||||
CTL_UNITS_MEMORY_BYTES = 8,
|
||||
CTL_UNITS_ANGULAR_SPEED_RPM = 9,
|
||||
CTL_UNITS_POWER_MILLIWATTS = 10,
|
||||
CTL_UNITS_PERCENT = 11,
|
||||
CTL_UNITS_MEM_SPEED_GBPS = 12,
|
||||
CTL_UNITS_VOLTAGE_MILLIVOLTS = 13,
|
||||
CTL_UNITS_BANDWIDTH_MBPS = 14,
|
||||
CTL_UNITS_UNKNOWN = 0x4800FFFF
|
||||
}
|
||||
|
||||
public static ctl_api_handle_t ApiHandle { get; private set; }
|
||||
|
||||
// Public interface
|
||||
public static bool IsAvailable { get; private set; }
|
||||
|
||||
public static bool IsInitialized { get; private set; }
|
||||
|
||||
// P/Invoke declarations
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
private static extern int ctlInit(ref ctl_init_args_t pInitDesc, ref ctl_api_handle_t phAPIHandle);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
private static extern int ctlEnumerateDevices(ctl_api_handle_t hAPIHandle, ref uint pCount, [Out] ctl_device_adapter_handle_t[] phDevices);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlGetDeviceProperties(ctl_device_adapter_handle_t hDAhandle, ref ctl_device_adapter_properties_t pProperties);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlPowerTelemetryGet(ctl_device_adapter_handle_t hDeviceHandle, ref ctl_power_telemetry_t pTelemetryInfo);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlEnumFans(ctl_device_adapter_handle_t hDAhandle, ref uint pCount, [Out] ctl_fan_handle_t[] phFan);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlFanGetState(ctl_fan_handle_t hFan, ctl_fan_speed_units_t units, ref int pSpeed);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlFanGetProperties(ctl_fan_handle_t hFan, ref ctl_fan_properties_t pProperties);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlEnumFrequencyDomains(ctl_device_adapter_handle_t hDAhandle, ref uint pCount, [Out] ctl_freq_handle_t[] phFrequency);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlFrequencyGetProperties(ctl_freq_handle_t hFrequency, ref ctl_freq_properties_t pProperties);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
public static extern int ctlFrequencyGetState(ctl_freq_handle_t hFrequency, ref ctl_freq_state_t pState);
|
||||
|
||||
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
||||
private static extern int ctlClose(ctl_api_handle_t hAPIHandle);
|
||||
|
||||
private static bool GclMethodExists(string gclMethod)
|
||||
{
|
||||
IntPtr module = Kernel32.LoadLibrary(DllName);
|
||||
if (module != IntPtr.Zero)
|
||||
{
|
||||
bool result = Kernel32.GetProcAddress(module, gclMethod) != IntPtr.Zero;
|
||||
Kernel32.FreeLibrary(module);
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Initialize()
|
||||
{
|
||||
if (!IsAvailable)
|
||||
return false;
|
||||
|
||||
if (IsInitialized)
|
||||
return true;
|
||||
|
||||
var initArgs = new ctl_init_args_t();
|
||||
initArgs.Size = (uint)Marshal.SizeOf(typeof(ctl_init_args_t));
|
||||
initArgs.Version = 0;
|
||||
initArgs.AppVersion = CTL_IMPL_VERSION;
|
||||
initArgs.flags = (uint)ctl_init_flag_t.CTL_INIT_FLAG_USE_LEVEL_ZERO;
|
||||
|
||||
var apiHandle = new ctl_api_handle_t();
|
||||
int result = ctlInit(ref initArgs, ref apiHandle);
|
||||
|
||||
if (result != (int)ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
return false;
|
||||
|
||||
ApiHandle = apiHandle;
|
||||
IsInitialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static ctl_device_adapter_handle_t[] GetDeviceHandles()
|
||||
{
|
||||
if (!IsInitialized && (!Initialize()))
|
||||
return Array.Empty<ctl_device_adapter_handle_t>();
|
||||
|
||||
// First call to get the device count
|
||||
uint count = 0;
|
||||
int result = ctlEnumerateDevices(ApiHandle, ref count, null);
|
||||
count = Math.Min(count, MAX_DEVICES);
|
||||
|
||||
if (result != (int)ctl_result_t.CTL_RESULT_SUCCESS || count == 0)
|
||||
return Array.Empty<ctl_device_adapter_handle_t>();
|
||||
|
||||
// Second call to get the actual device handles
|
||||
var handles = new ctl_device_adapter_handle_t[count];
|
||||
result = ctlEnumerateDevices(ApiHandle, ref count, handles);
|
||||
|
||||
if (result != (int)ctl_result_t.CTL_RESULT_SUCCESS)
|
||||
return Array.Empty<ctl_device_adapter_handle_t>();
|
||||
|
||||
return handles;
|
||||
}
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
try
|
||||
{
|
||||
ctlClose(ApiHandle);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsInitialized = false;
|
||||
ApiHandle = new ctl_api_handle_t();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unions
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct ctl_data_value_t
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public sbyte data8;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public byte datau8;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public short data16;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public ushort datau16;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public int data32;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public uint datau32;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public long data64;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public ulong datau64;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public float datafloat;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public double datadouble;
|
||||
}
|
||||
|
||||
// Structures
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_api_handle_t
|
||||
{
|
||||
private IntPtr pNext;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_application_id_t
|
||||
{
|
||||
public uint Data1;
|
||||
public ushort Data2;
|
||||
public ushort Data3;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
|
||||
public byte[] Data4;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_init_args_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public uint AppVersion;
|
||||
public uint flags;
|
||||
public uint SupportedVersion;
|
||||
public ctl_application_id_t ApplicationUID;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_device_adapter_handle_t
|
||||
{
|
||||
private IntPtr pNext;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_fan_handle_t
|
||||
{
|
||||
private IntPtr pNext;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_fan_speed_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public int speed;
|
||||
public ctl_fan_speed_units_t units;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_fan_properties_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public bool canControl;
|
||||
public uint supportedModes;
|
||||
public uint supportedUnits;
|
||||
public int maxRPM;
|
||||
public int maxPoints;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_freq_handle_t
|
||||
{
|
||||
private IntPtr pNext;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_freq_properties_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public ctl_freq_domain_t type;
|
||||
public bool canControl;
|
||||
public double min;
|
||||
public double max;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_freq_state_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public double currentVoltage;
|
||||
public double request;
|
||||
public double tdp;
|
||||
public double efficient;
|
||||
public double actual;
|
||||
public uint throttleReasons;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_device_adapter_properties_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public IntPtr pDeviceID;
|
||||
public uint device_id_size;
|
||||
public ctl_device_type_t device_type;
|
||||
public uint supported_subfunction_flags;
|
||||
public ulong driver_version;
|
||||
public ctl_firmware_version_t firmware_version;
|
||||
public uint pci_vendor_id;
|
||||
public uint pci_device_id;
|
||||
public uint rev_id;
|
||||
public uint num_eus_per_sub_slice;
|
||||
public uint num_sub_slices_per_slice;
|
||||
public uint num_slices;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CTL_MAX_DEVICE_NAME_LEN)]
|
||||
public string name;
|
||||
|
||||
public uint graphics_adapter_properties;
|
||||
public uint Frequency;
|
||||
public ushort pci_subsys_id;
|
||||
public ushort pci_subsys_vendor_id;
|
||||
public ctl_adapter_bdf_t adapter_bdf;
|
||||
public uint num_xe_cores;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CTL_MAX_RESERVED_SIZE)]
|
||||
public byte[] reserved;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_adapter_bdf_t
|
||||
{
|
||||
public byte bus;
|
||||
public byte device;
|
||||
public byte function;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_firmware_version_t
|
||||
{
|
||||
public ulong major_version;
|
||||
public ulong minor_version;
|
||||
public ulong build_number;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_oc_telemetry_item_t
|
||||
{
|
||||
public bool bSupported;
|
||||
public ctl_units_t units;
|
||||
public ctl_data_type_t type;
|
||||
public ctl_data_value_t value;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_psu_info_t
|
||||
{
|
||||
public bool bSupported;
|
||||
public ctl_psu_type_t psuType;
|
||||
public ctl_oc_telemetry_item_t energyCounter;
|
||||
public ctl_oc_telemetry_item_t voltage;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ctl_power_telemetry_t
|
||||
{
|
||||
public uint Size;
|
||||
public byte Version;
|
||||
public ctl_oc_telemetry_item_t timeStamp;
|
||||
public ctl_oc_telemetry_item_t gpuEnergyCounter;
|
||||
public ctl_oc_telemetry_item_t gpuVoltage;
|
||||
public ctl_oc_telemetry_item_t gpuCurrentClockFrequency;
|
||||
public ctl_oc_telemetry_item_t gpuCurrentTemperature;
|
||||
public ctl_oc_telemetry_item_t globalActivityCounter;
|
||||
public ctl_oc_telemetry_item_t renderComputeActivityCounter;
|
||||
public ctl_oc_telemetry_item_t mediaActivityCounter;
|
||||
public bool gpuPowerLimited;
|
||||
public bool gpuTemperatureLimited;
|
||||
public bool gpuCurrentLimited;
|
||||
public bool gpuVoltageLimited;
|
||||
public bool gpuUtilizationLimited;
|
||||
public ctl_oc_telemetry_item_t vramEnergyCounter;
|
||||
public ctl_oc_telemetry_item_t vramVoltage;
|
||||
public ctl_oc_telemetry_item_t vramCurrentClockFrequency;
|
||||
public ctl_oc_telemetry_item_t vramCurrentEffectiveFrequency;
|
||||
public ctl_oc_telemetry_item_t vramReadBandwidthCounter;
|
||||
public ctl_oc_telemetry_item_t vramWriteBandwidthCounter;
|
||||
public ctl_oc_telemetry_item_t vramCurrentTemperature;
|
||||
public bool vramPowerLimited;
|
||||
public bool vramTemperatureLimited;
|
||||
public bool vramCurrentLimited;
|
||||
public bool vramVoltageLimited;
|
||||
public bool vramUtilizationLimited;
|
||||
public ctl_oc_telemetry_item_t totalCardEnergyCounter;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CTL_PSU_COUNT)]
|
||||
public ctl_psu_info_t[] psu;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CTL_FAN_COUNT)]
|
||||
public ctl_oc_telemetry_item_t[] fanSpeed;
|
||||
|
||||
public ctl_oc_telemetry_item_t gpuVrTemp;
|
||||
public ctl_oc_telemetry_item_t vramVrTemp;
|
||||
public ctl_oc_telemetry_item_t saVrTemp;
|
||||
public ctl_oc_telemetry_item_t gpuEffectiveClock;
|
||||
public ctl_oc_telemetry_item_t gpuOverVoltagePercent;
|
||||
public ctl_oc_telemetry_item_t gpuPowerPercent;
|
||||
public ctl_oc_telemetry_item_t gpuTemperaturePercent;
|
||||
public ctl_oc_telemetry_item_t vramReadBandwidth;
|
||||
public ctl_oc_telemetry_item_t vramWriteBandwidth;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user