Experimental GPU overclock

This commit is contained in:
Serge
2023-05-06 14:40:52 +02:00
parent 8e1099545a
commit c61f4d1608
497 changed files with 46937 additions and 232 deletions

View File

@@ -0,0 +1,30 @@
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the accelerated graphics connection
/// </summary>
public class AGPInformation
{
internal AGPInformation(int aperture, int currentRate)
{
ApertureInMB = aperture;
CurrentRate = currentRate;
}
/// <summary>
/// Gets AGP aperture in megabytes
/// </summary>
public int ApertureInMB { get; }
/// <summary>
/// Gets current AGP Rate (0 = AGP not present, 1 = 1x, 2 = 2x, etc.)
/// </summary>
public int CurrentRate { get; }
/// <inheritdoc />
public override string ToString()
{
return $"AGP Aperture: {ApertureInMB}MB, Current Rate: {CurrentRate}x";
}
}
}

View File

@@ -0,0 +1,201 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the ECC memory
/// </summary>
public class ECCMemoryInformation
{
internal ECCMemoryInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the number of aggregated ECC memory double bit errors
/// </summary>
public ulong AggregatedDoubleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).AggregatedErrors.DoubleBitErrors;
}
}
/// <summary>
/// Gets the number of aggregated ECC memory single bit errors
/// </summary>
public ulong AggregatedSingleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).AggregatedErrors.SingleBitErrors;
}
}
/// <summary>
/// Gets the ECC memory configuration in regard to how changes are applied
/// </summary>
public ECCConfiguration Configuration
{
get
{
try
{
return GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).ConfigurationOptions;
}
catch
{
return ECCConfiguration.NotSupported;
}
}
}
/// <summary>
/// Gets the number of current ECC memory double bit errors
/// </summary>
public ulong CurrentDoubleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).CurrentErrors.DoubleBitErrors;
}
}
/// <summary>
/// Gets the number of current ECC memory single bit errors
/// </summary>
public ulong CurrentSingleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).CurrentErrors.SingleBitErrors;
}
}
/// <summary>
/// Gets a boolean value indicating if ECC memory error correction is enabled
/// </summary>
public bool IsEnabled
{
get => IsSupported &&
GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).IsEnabled &&
GPUApi.GetECCConfigurationInfo(PhysicalGPU.Handle).IsEnabled;
}
/// <summary>
/// Gets a boolean value indicating if ECC memory is enabled by default
/// </summary>
public bool IsEnabledByDefault
{
get => IsSupported &&
GPUApi.GetECCConfigurationInfo(PhysicalGPU.Handle).IsEnabledByDefault;
}
/// <summary>
/// Gets a boolean value indicating if ECC memory is supported and available
/// </summary>
public bool IsSupported
{
get
{
try
{
return GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).IsSupported;
}
catch
{
return false;
}
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
if (!IsSupported)
{
return "[Not Supported]";
}
if (!IsEnabled)
{
return "[Disabled]";
}
return
$"{CurrentSingleBitErrors}, {CurrentDoubleBitErrors} ({AggregatedSingleBitErrors}, {AggregatedDoubleBitErrors})";
}
/// <summary>
/// Clears aggregated error counters.
/// </summary>
public void ClearAggregatedErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, false, true);
}
/// <summary>
/// Clears current error counters.
/// </summary>
public void ClearCurrentErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, true, false);
}
/// <summary>
/// Clears all error counters.
/// </summary>
public void ClearErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, true, true);
}
/// <summary>
/// Disables ECC memory error correction.
/// </summary>
/// <param name="immediate">A boolean value to indicate if this change should get applied immediately</param>
public void Disable(bool immediate)
{
GPUApi.SetECCConfiguration(PhysicalGPU.Handle, false, immediate);
}
/// <summary>
/// Enables ECC memory error correction.
/// </summary>
/// <param name="immediate">A boolean value to indicate if this change should get applied immediately</param>
public void Enable(bool immediate)
{
GPUApi.SetECCConfiguration(PhysicalGPU.Handle, true, immediate);
}
}
}

View File

@@ -0,0 +1,115 @@
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains physical GPU architect information
/// </summary>
public class GPUArchitectInformation
{
internal GPUArchitectInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets total number of cores defined for this GPU, or zero for older architectures
/// </summary>
public int NumberOfCores
{
get => (int) GPUApi.GetGPUCoreCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of graphics processing clusters (aka GPU Partitions)
/// </summary>
public int NumberOfGPC
{
get => (int) GPUApi.GetPartitionCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of render output units
/// </summary>
public int NumberOfROPs
{
get => (int) GPUApi.GetROPCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of shader pipelines
/// </summary>
public int NumberOfShaderPipelines
{
get => (int) GPUApi.GetShaderPipeCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of shader sub pipelines
/// </summary>
public int NumberOfShaderSubPipelines
{
get => (int) GPUApi.GetShaderSubPipeCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of video processing engines
/// </summary>
public int NumberOfVPEs
{
get => (int) GPUApi.GetVPECount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the GPU revision number (should be displayed as a hex string)
/// </summary>
public int Revision
{
get => (int) GPUApi.GetArchitectInfo(PhysicalGPU.Handle).Revision;
}
/// <summary>
/// Gets the GPU short name (aka Codename)
/// </summary>
public string ShortName
{
get => GPUApi.GetShortName(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of streaming multiprocessors
/// </summary>
public int TotalNumberOfSMs
{
get => (int) GPUApi.GetTotalSMCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of streaming processors
/// </summary>
public int TotalNumberOfSPs
{
get => (int) GPUApi.GetTotalSPCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of texture processing clusters
/// </summary>
public int TotalNumberOfTPCs
{
get => (int) GPUApi.GetTotalTPCCount(PhysicalGPU.Handle);
}
/// <inheritdoc />
public override string ToString()
{
return $"[{ShortName} REV{Revision:X}] Cores: {NumberOfCores}";
}
}
}

View File

@@ -0,0 +1,118 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU bus
/// </summary>
public class GPUBusInformation
{
internal GPUBusInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets accelerated graphics port information
/// </summary>
public AGPInformation AGPInformation
{
get
{
if (BusType != GPUBusType.AGP)
{
return null;
}
return new AGPInformation(
GPUApi.GetAGPAperture(PhysicalGPU.Handle),
GPUApi.GetCurrentAGPRate(PhysicalGPU.Handle)
);
}
}
/// <summary>
/// Gets the bus identification
/// </summary>
public int BusId
{
get => GPUApi.GetBusId(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the bus slot identification
/// </summary>
public int BusSlot
{
get => GPUApi.GetBusSlotId(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the the bus type
/// </summary>
public GPUBusType BusType
{
get => GPUApi.GetBusType(PhysicalGPU.Handle);
}
/// <summary>
/// Gets number of PCIe lanes being used for the PCIe interface downstream
/// </summary>
public int CurrentPCIeLanes
{
get
{
if (BusType == GPUBusType.PCIExpress)
{
return GPUApi.GetCurrentPCIEDownStreamWidth(PhysicalGPU.Handle);
}
return 0;
}
}
/// <summary>
/// Gets GPU interrupt number
/// </summary>
public int IRQ
{
get => GPUApi.GetIRQ(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the PCI identifiers
/// </summary>
public PCIIdentifiers PCIIdentifiers
{
get
{
if (BusType == GPUBusType.FPCI || BusType == GPUBusType.PCI || BusType == GPUBusType.PCIExpress)
{
GPUApi.GetPCIIdentifiers(
PhysicalGPU.Handle,
out var deviceId,
out var subSystemId,
out var revisionId,
out var extDeviceId
);
return new PCIIdentifiers(deviceId, subSystemId, revisionId, (int) extDeviceId);
}
return null;
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{BusType}] Bus #{BusId}, Slot #{BusSlot}";
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a GPU cooler entry
/// </summary>
public class GPUCooler
{
internal GPUCooler(int coolerId, PrivateCoolerSettingsV1.CoolerSetting coolerSetting, int currentRPM = -1)
{
CoolerId = coolerId;
CurrentLevel = (int) coolerSetting.CurrentLevel;
DefaultMinimumLevel = (int) coolerSetting.DefaultMinimumLevel;
DefaultMaximumLevel = (int) coolerSetting.DefaultMaximumLevel;
CurrentMinimumLevel = (int) coolerSetting.CurrentMinimumLevel;
CurrentMaximumLevel = (int) coolerSetting.CurrentMaximumLevel;
CoolerType = coolerSetting.CoolerType;
CoolerController = coolerSetting.CoolerController;
DefaultPolicy = coolerSetting.DefaultPolicy;
CurrentPolicy = coolerSetting.CurrentPolicy;
Target = coolerSetting.Target;
ControlMode = coolerSetting.ControlMode;
CurrentFanSpeedInRPM = currentRPM;
}
// ReSharper disable once TooManyDependencies
internal GPUCooler(
PrivateFanCoolersInfoV1.FanCoolersInfoEntry infoEntry,
PrivateFanCoolersStatusV1.FanCoolersStatusEntry statusEntry,
PrivateFanCoolersControlV1.FanCoolersControlEntry controlEntry)
{
if (infoEntry.CoolerId != statusEntry.CoolerId || statusEntry.CoolerId != controlEntry.CoolerId)
{
throw new ArgumentException("Passed arguments are meant to be for different coolers.");
}
CoolerId = (int) statusEntry.CoolerId;
CurrentLevel = (int) statusEntry.CurrentLevel;
DefaultMinimumLevel = (int) statusEntry.CurrentMinimumLevel;
DefaultMaximumLevel = (int) statusEntry.CurrentMaximumLevel;
CurrentMinimumLevel = (int) statusEntry.CurrentMinimumLevel;
CurrentMaximumLevel = (int) statusEntry.CurrentMaximumLevel;
CoolerType = CoolerType.Fan;
CoolerController = CoolerController.Internal;
DefaultPolicy = CoolerPolicy.None;
CurrentPolicy = controlEntry.ControlMode == FanCoolersControlMode.Manual
? CoolerPolicy.Manual
: CoolerPolicy.None;
Target = CoolerTarget.All;
ControlMode = CoolerControlMode.Variable;
CurrentFanSpeedInRPM = (int) statusEntry.CurrentRPM;
}
/// <summary>
/// Gets the cooler control mode
/// </summary>
public CoolerControlMode ControlMode { get; }
/// <summary>
/// Gets the cooler controller
/// </summary>
public CoolerController CoolerController { get; }
/// <summary>
/// Gets the cooler identification number or index
/// </summary>
public int CoolerId { get; }
/// <summary>
/// Gets the cooler type
/// </summary>
public CoolerType CoolerType { get; }
/// <summary>
/// Gets the GPU fan speed in revolutions per minute
/// </summary>
public int CurrentFanSpeedInRPM { get; }
/// <summary>
/// Gets the cooler current level in percentage
/// </summary>
public int CurrentLevel { get; }
/// <summary>
/// Gets the cooler current maximum level in percentage
/// </summary>
public int CurrentMaximumLevel { get; }
/// <summary>
/// Gets the cooler current minimum level in percentage
/// </summary>
public int CurrentMinimumLevel { get; }
/// <summary>
/// Gets the cooler current policy
/// </summary>
public CoolerPolicy CurrentPolicy { get; }
/// <summary>
/// Gets the cooler default maximum level in percentage
/// </summary>
public int DefaultMaximumLevel { get; }
/// <summary>
/// Gets the cooler default minimum level in percentage
/// </summary>
public int DefaultMinimumLevel { get; }
/// <summary>
/// Gets the cooler default policy
/// </summary>
public CoolerPolicy DefaultPolicy { get; }
/// <summary>
/// Gets the cooler target
/// </summary>
public CoolerTarget Target { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{CoolerId} @ {CoolerController}] {Target}: {CurrentLevel}%";
}
}
}

View File

@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU coolers and current fan speed
/// </summary>
public class GPUCoolerInformation
{
internal GPUCoolerInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
// TODO: Add Support For Pascal Only Policy Table Method
// TODO: GPUApi.GetCoolerPolicyTable & GPUApi.SetCoolerPolicyTable & GPUApi.RestoreCoolerPolicyTable
// TODO: Better support of ClientFanCoolers set of APIs
}
/// <summary>
/// Gets a list of all available coolers along with their current settings and status
/// </summary>
public IEnumerable<GPUCooler> Coolers
{
get
{
PrivateCoolerSettingsV1? settings = null;
try
{
settings = GPUApi.GetCoolerSettings(PhysicalGPU.Handle);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
if (settings != null)
{
for (var i = 0; i < settings.Value.CoolerSettings.Length; i++)
{
if (i == 0)
{
var currentRPM = -1;
try
{
currentRPM = (int)GPUApi.GetTachReading(PhysicalGPU.Handle);
}
catch (NVIDIAApiException)
{
// ignored
}
if (currentRPM >= 0)
{
yield return new GPUCooler(
i,
settings.Value.CoolerSettings[i],
currentRPM
);
continue;
}
}
yield return new GPUCooler(
i,
settings.Value.CoolerSettings[i]
);
}
yield break;
}
PrivateFanCoolersStatusV1? status = null;
PrivateFanCoolersInfoV1? info = null;
PrivateFanCoolersControlV1? control = null;
try
{
status = GPUApi.GetClientFanCoolersStatus(PhysicalGPU.Handle);
info = GPUApi.GetClientFanCoolersInfo(PhysicalGPU.Handle);
control = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
if (status != null && info != null && control != null)
{
for (var i = 0; i < status.Value.FanCoolersStatusEntries.Length; i++)
{
if (info.Value.FanCoolersInfoEntries.Length > i &&
control.Value.FanCoolersControlEntries.Length > i)
{
yield return new GPUCooler(
info.Value.FanCoolersInfoEntries[i],
status.Value.FanCoolersStatusEntries[i],
control.Value.FanCoolersControlEntries[i]
);
}
}
yield break;
}
throw new NVIDIAApiException(Status.NotSupported);
}
}
/// <summary>
/// Gets the GPU fan speed in revolutions per minute
/// </summary>
public int CurrentFanSpeedInRPM
{
get
{
try
{
return (int) GPUApi.GetTachReading(PhysicalGPU.Handle);
}
catch
{
return Coolers.FirstOrDefault(cooler => cooler.Target == CoolerTarget.All)?.CurrentFanSpeedInRPM ??
0;
}
}
}
/// <summary>
/// Gets the current fan speed in percentage if available
/// </summary>
public int CurrentFanSpeedLevel
{
get
{
try
{
return (int) GPUApi.GetCurrentFanSpeedLevel(PhysicalGPU.Handle);
}
catch
{
return Coolers.FirstOrDefault(cooler => cooler.Target == CoolerTarget.All)?.CurrentLevel ?? 0;
}
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
return $"{CurrentFanSpeedInRPM} RPM ({CurrentFanSpeedLevel}%)";
}
/// <summary>
/// Resets all cooler settings to default.
/// </summary>
public void RestoreCoolerSettingsToDefault()
{
RestoreCoolerSettingsToDefault(Coolers.Select(cooler => cooler.CoolerId).ToArray());
}
/// <summary>
/// Resets one or more cooler settings to default.
/// </summary>
/// <param name="coolerIds">The cooler identification numbers (indexes) to reset their settings to default.</param>
public void RestoreCoolerSettingsToDefault(params int[] coolerIds)
{
var availableCoolerIds = Coolers.Select(cooler => cooler.CoolerId).ToArray();
if (coolerIds.Any(i => !availableCoolerIds.Contains(i)))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerIds));
}
try
{
GPUApi.RestoreCoolerSettings(PhysicalGPU.Handle, coolerIds.Select(i => (uint) i).ToArray());
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => coolerIds.Contains((int) entry.CoolerId)
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
FanCoolersControlMode.Auto
)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler settings by modifying the policy and the current level
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="policy">The new cooler policy.</param>
/// <param name="newLevel">The new cooler level. Valid only if policy is set to manual.</param>
// ReSharper disable once TooManyDeclarations
public void SetCoolerSettings(int coolerId, CoolerPolicy policy, int newLevel)
{
if (Coolers.All(cooler => cooler.CoolerId != coolerId))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerId));
}
try
{
GPUApi.SetCoolerLevels(
PhysicalGPU.Handle,
(uint) coolerId,
new PrivateCoolerLevelsV1(new[]
{
new PrivateCoolerLevelsV1.CoolerLevel(policy, (uint) newLevel)
}
),
1
);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => entry.CoolerId == coolerId
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
policy == CoolerPolicy.Manual
? FanCoolersControlMode.Manual
: FanCoolersControlMode.Auto,
policy == CoolerPolicy.Manual ? (uint)newLevel : 0u)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler setting by modifying the policy
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="policy">The new cooler policy.</param>
// ReSharper disable once TooManyDeclarations
public void SetCoolerSettings(int coolerId, CoolerPolicy policy)
{
if (Coolers.All(cooler => cooler.CoolerId != coolerId))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerId));
}
try
{
GPUApi.SetCoolerLevels(
PhysicalGPU.Handle,
(uint) coolerId,
new PrivateCoolerLevelsV1(new[]
{
new PrivateCoolerLevelsV1.CoolerLevel(policy)
}
),
1
);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => entry.CoolerId == coolerId
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
policy == CoolerPolicy.Manual
? FanCoolersControlMode.Manual
: FanCoolersControlMode.Auto)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler settings by modifying the policy to manual and sets a new level
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="newLevel">The new cooler level.</param>
public void SetCoolerSettings(int coolerId, int newLevel)
{
SetCoolerSettings(coolerId, CoolerPolicy.Manual, newLevel);
}
}
}

View File

@@ -0,0 +1,222 @@
using System;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information regarding the available and total memory as well as the type of memory and other information
/// regarding the GPU RAM and frame buffer
/// </summary>
public class GPUMemoryInformation : IDisplayDriverMemoryInfo
{
internal GPUMemoryInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the frame buffer bandwidth
/// </summary>
public int FrameBufferBandwidth
{
get
{
GPUApi.GetFrameBufferWidthAndLocation(PhysicalGPU.Handle, out var width, out _);
return (int) width;
}
}
/// <summary>
/// Gets the frame buffer location index
/// </summary>
public int FrameBufferLocation
{
get
{
GPUApi.GetFrameBufferWidthAndLocation(PhysicalGPU.Handle, out _, out var location);
return (int) location;
}
}
/// <summary>
/// Gets the internal clock to bus clock factor based on the type of RAM
/// </summary>
public int InternalClockToBusClockFactor
{
get => GetMemoryBusClockFactor(RAMType);
}
/// <summary>
/// Gets the internal clock to transfer rate factor based on the type of RAM
/// </summary>
public int InternalClockToTransferRateFactor
{
get => GetMemoryTransferRateFactor(RAMType);
}
/// <summary>
/// Gets GPU physical frame buffer size in KB. This does NOT include any system RAM that may be dedicated for use by
/// the GPU.
/// </summary>
public int PhysicalFrameBufferSizeInkB
{
get => GPUApi.GetPhysicalFrameBufferSize(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the number of memory banks
/// </summary>
public uint RAMBanks
{
get => GPUApi.GetRAMBankCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory bus width
/// </summary>
public uint RAMBusWidth
{
get => GPUApi.GetRAMBusWidth(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory maker (brand)
/// </summary>
public GPUMemoryMaker RAMMaker
{
get => GPUApi.GetRAMMaker(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory type
/// </summary>
public GPUMemoryType RAMType
{
get => GPUApi.GetRAMType(PhysicalGPU.Handle);
}
/// <summary>
/// Gets virtual size of frame-buffer in KB for this GPU. This includes the physical RAM plus any system RAM that has
/// been dedicated for use by the GPU.
/// </summary>
public int VirtualFrameBufferSizeInkB
{
get => GPUApi.GetVirtualFrameBufferSize(PhysicalGPU.Handle);
}
/// <inheritdoc />
public uint AvailableDedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).AvailableDedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint CurrentAvailableDedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).CurrentAvailableDedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint DedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).DedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint SharedSystemMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).SharedSystemMemoryInkB;
}
/// <inheritdoc />
public uint SystemVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).SystemVideoMemoryInkB;
}
/// <summary>
/// Gets the memory bus clock to internal memory clock factor
/// </summary>
/// <param name="memoryType"></param>
/// <returns>The value of X in X(InternalMemoryClock)=(BusMemoryClock)</returns>
public static int GetMemoryBusClockFactor(GPUMemoryType memoryType)
{
switch (memoryType)
{
case GPUMemoryType.SDRAM:
// Bus Clocks Per Internal Clock = 1
return 1;
case GPUMemoryType.DDR1:
case GPUMemoryType.DDR2:
case GPUMemoryType.DDR3:
case GPUMemoryType.GDDR2:
case GPUMemoryType.GDDR3:
case GPUMemoryType.GDDR4:
case GPUMemoryType.LPDDR2:
case GPUMemoryType.GDDR5:
case GPUMemoryType.GDDR5X:
// Bus Clocks Per Internal Clock = 2
return 2;
default:
throw new ArgumentOutOfRangeException(nameof(memoryType));
}
}
/// <summary>
/// Gets the number of transfers per internal memory clock factor
/// </summary>
/// <param name="memoryType"></param>
/// <returns>The value of X in X(InternalMemoryClock)=(OperationsPerSecond)</returns>
public static int GetMemoryTransferRateFactor(GPUMemoryType memoryType)
{
switch (memoryType)
{
case GPUMemoryType.SDRAM:
// Transfers Per Internal Clock = 1
return 1;
case GPUMemoryType.DDR1:
case GPUMemoryType.DDR2:
case GPUMemoryType.DDR3:
case GPUMemoryType.GDDR2:
case GPUMemoryType.GDDR3:
case GPUMemoryType.GDDR4:
case GPUMemoryType.LPDDR2:
// Transfers Per Internal Clock = 1
return 2;
case GPUMemoryType.GDDR5:
// Transfers Per Internal Clock = 2
return 4;
case GPUMemoryType.GDDR5X:
// Transfers Per Internal Clock = 4
return 8;
default:
throw new ArgumentOutOfRangeException(nameof(memoryType));
}
}
/// <inheritdoc />
public override string ToString()
{
return
$"[{RAMMaker} {RAMType}] Total: {AvailableDedicatedVideoMemoryInkB:N0} kB - Available: {CurrentAvailableDedicatedVideoMemoryInkB:N0} kB";
}
}
}

View File

@@ -0,0 +1,264 @@
using System;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a single GPU output
/// </summary>
public class GPUOutput : IEquatable<GPUOutput>
{
internal GPUOutput(OutputId outputId, PhysicalGPUHandle gpuHandle)
{
OutputId = outputId;
OutputType = !gpuHandle.IsNull ? GPUApi.GetOutputType(gpuHandle, outputId) : OutputType.Unknown;
PhysicalGPU = new PhysicalGPU(gpuHandle);
}
internal GPUOutput(OutputId outputId, PhysicalGPU gpu)
: this(outputId, gpu?.Handle ?? PhysicalGPUHandle.DefaultHandle)
{
PhysicalGPU = gpu;
}
/// <summary>
/// Gets the corresponding Digital Vibrance Control information
/// </summary>
public DVCInformation DigitalVibranceControl
{
get => new DVCInformation(OutputId);
}
/// <summary>
/// Gets the corresponding HUE information
/// </summary>
public HUEInformation HUEControl
{
get => new HUEInformation(OutputId);
}
/// <summary>
/// Gets the output identification as a single bit unsigned integer
/// </summary>
public OutputId OutputId { get; }
/// <summary>
/// Gets the output type
/// </summary>
public OutputType OutputType { get; }
/// <summary>
/// Gets the corresponding physical GPU
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public bool Equals(GPUOutput other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return PhysicalGPU.Equals(other.PhysicalGPU) && OutputId == other.OutputId;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(GPUOutput left, GPUOutput right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(GPUOutput left, GPUOutput right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((GPUOutput) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
return ((PhysicalGPU != null ? PhysicalGPU.GetHashCode() : 0) * 397) ^ (int) OutputId;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"{OutputId} {OutputType} @ {PhysicalGPU}";
}
/// <summary>
/// Overrides the refresh rate on this output.
/// The new refresh rate can be applied right away or deferred to be applied with the next OS
/// mode-set.
/// The override is good for only one mode-set (regardless whether it's deferred or immediate).
/// </summary>
/// <param name="refreshRate">The refresh rate to be applied.</param>
/// <param name="isDeferred">
/// A boolean value indicating if the refresh rate override should be deferred to the next OS
/// mode-set.
/// </param>
public void OverrideRefreshRate(float refreshRate, bool isDeferred = false)
{
DisplayApi.SetRefreshRateOverride(OutputId, refreshRate, isDeferred);
}
/// <summary>
/// Reads data from the I2C bus
/// </summary>
/// <param name="portId">The port id on which device is connected</param>
/// <param name="useDDCPort">A boolean value indicating that the DDC port should be used instead of the communication port</param>
/// <param name="deviceAddress">The device I2C slave address</param>
/// <param name="registerAddress">The target I2C register address</param>
/// <param name="readDataLength">The length of the buffer to allocate for the read operation.</param>
/// <param name="speed">The target speed of the transaction in kHz</param>
public byte[] ReadI2C(
byte? portId,
bool useDDCPort,
byte deviceAddress,
byte[] registerAddress,
uint readDataLength,
I2CSpeed speed = I2CSpeed.Default
)
{
try
{
// ReSharper disable once InconsistentNaming
var i2cInfoV3 = new I2CInfoV3(
OutputId,
portId,
useDDCPort,
deviceAddress,
registerAddress,
readDataLength,
speed
);
return PhysicalGPU.ReadI2C(i2cInfoV3);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.IncompatibleStructureVersion || portId != null)
{
throw;
}
// ignore
}
// ReSharper disable once InconsistentNaming
var i2cInfoV2 = new I2CInfoV2(
OutputId,
useDDCPort,
deviceAddress,
registerAddress,
readDataLength,
speed
);
return PhysicalGPU.ReadI2C(i2cInfoV2);
}
/// <summary>
/// Writes data to the I2C bus
/// </summary>
/// <param name="portId">The port id on which device is connected</param>
/// <param name="useDDCPort">A boolean value indicating that the DDC port should be used instead of the communication port</param>
/// <param name="deviceAddress">The device I2C slave address</param>
/// <param name="registerAddress">The target I2C register address</param>
/// <param name="data">The payload data</param>
/// <param name="speed">The target speed of the transaction in kHz</param>
public void WriteI2C(
byte? portId,
bool useDDCPort,
byte deviceAddress,
byte[] registerAddress,
byte[] data,
I2CSpeed speed = I2CSpeed.Default
)
{
try
{
// ReSharper disable once InconsistentNaming
var i2cInfoV3 = new I2CInfoV3(
OutputId,
portId,
useDDCPort,
deviceAddress,
registerAddress,
data,
speed
);
PhysicalGPU.WriteI2C(i2cInfoV3);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.IncompatibleStructureVersion || portId != null)
{
throw;
}
// ignore
}
// ReSharper disable once InconsistentNaming
var i2cInfoV2 = new I2CInfoV2(
OutputId,
useDDCPort,
deviceAddress,
registerAddress,
data,
speed
);
PhysicalGPU.WriteI2C(i2cInfoV2);
}
}
}

View File

@@ -0,0 +1,124 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information regarding the GPU performance control and limitations
/// </summary>
public class GPUPerformanceControl
{
internal GPUPerformanceControl(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the current active performance limitation
/// </summary>
public PerformanceLimit CurrentActiveLimit
{
get => GPUApi.PerformancePoliciesGetStatus(PhysicalGPU.Handle).PerformanceLimit;
}
/// <summary>
/// Gets the current performance decrease reason
/// </summary>
public PerformanceDecreaseReason CurrentPerformanceDecreaseReason
{
get => GPUApi.GetPerformanceDecreaseInfo(PhysicalGPU.Handle);
}
/// <summary>
/// Gets a boolean value indicating if no load limit is supported with this GPU
/// </summary>
public bool IsNoLoadLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsNoLoadLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if power limit is supported with this GPU
/// </summary>
public bool IsPowerLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsPowerLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if temperature limit is supported with this GPU
/// </summary>
public bool IsTemperatureLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsTemperatureLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if voltage limit is supported with this GPU
/// </summary>
public bool IsVoltageLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsVoltageLimitSupported;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets information regarding possible power limit policies and their acceptable range
/// </summary>
public IEnumerable<GPUPowerLimitInfo> PowerLimitInformation
{
get
{
return GPUApi.ClientPowerPoliciesGetInfo(PhysicalGPU.Handle).PowerPolicyInfoEntries
.Select(entry => new GPUPowerLimitInfo(entry));
}
}
/// <summary>
/// Gets the current active power limit policies
/// </summary>
public IEnumerable<GPUPowerLimitPolicy> PowerLimitPolicies
{
get
{
// TODO: GPUApi.ClientPowerPoliciesSetStatus();
return GPUApi.ClientPowerPoliciesGetStatus(PhysicalGPU.Handle).PowerPolicyStatusEntries
.Select(entry => new GPUPowerLimitPolicy(entry));
}
}
/// <summary>
/// Gets information regarding possible thermal limit policies and their acceptable range
/// </summary>
public IEnumerable<GPUThermalLimitInfo> ThermalLimitInformation
{
get
{
return GPUApi.GetThermalPoliciesInfo(PhysicalGPU.Handle).ThermalPoliciesInfoEntries
.Select(entry => new GPUThermalLimitInfo(entry));
}
}
/// <summary>
/// Gets the current active thermal limit policies
/// </summary>
public IEnumerable<GPUThermalLimitPolicy> ThermalLimitPolicies
{
get
{
// TODO: GPUApi.SetThermalPoliciesStatus();
return GPUApi.GetThermalPoliciesStatus(PhysicalGPU.Handle).ThermalPoliciesStatusEntries
.Select(entry => new GPUThermalLimitPolicy(entry));
}
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Linq;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state
/// </summary>
public class GPUPerformanceState
{
// ReSharper disable once TooManyDependencies
internal GPUPerformanceState(
int index,
IPerformanceState20 performanceState,
IPerformanceStates20ClockEntry[] statesClockEntries,
IPerformanceStates20VoltageEntry[] baseVoltageEntries,
PCIeInformation pcieInformation)
{
StateIndex = index;
StateId = performanceState.StateId;
IsReadOnly = !performanceState.IsEditable;
Clocks = statesClockEntries.Select(entry => new GPUPerformanceStateClock(entry)).ToArray();
Voltages = baseVoltageEntries.Select(entry => new GPUPerformanceStateVoltage(entry)).ToArray();
PCIeInformation = pcieInformation;
}
/// <summary>
/// Gets a list of clocks associated with this performance state
/// </summary>
public GPUPerformanceStateClock[] Clocks { get; }
/// <summary>
/// Gets a boolean value indicating if this performance state is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets the PCI-e information regarding this performance state.
/// </summary>
public PCIeInformation PCIeInformation { get; }
/// <summary>
/// Gets the performance state identification
/// </summary>
public PerformanceStateId StateId { get; }
/// <summary>
/// Gets the state index
/// </summary>
public int StateIndex { get; }
/// <summary>
/// Gets a list of voltages associated with this performance state
/// </summary>
public GPUPerformanceStateVoltage[] Voltages { get; }
/// <inheritdoc />
public override string ToString()
{
if (IsReadOnly)
{
return $"{StateId} (ReadOnly)";
}
return StateId.ToString();
}
}
}

View File

@@ -0,0 +1,99 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state clock settings
/// </summary>
public class GPUPerformanceStateClock
{
internal GPUPerformanceStateClock(IPerformanceStates20ClockEntry states20ClockEntry)
{
ClockDomain = states20ClockEntry.DomainId;
IsReadOnly = !states20ClockEntry.IsEditable;
ClockDeltaInkHz = states20ClockEntry.FrequencyDeltaInkHz.DeltaValue;
ClockDeltaRangeInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyDeltaInkHz.DeltaRange.Minimum,
states20ClockEntry.FrequencyDeltaInkHz.DeltaRange.Maximum
);
if (states20ClockEntry.ClockType == PerformanceStates20ClockType.Range)
{
CurrentClockInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyRange.MinimumFrequencyInkHz,
states20ClockEntry.FrequencyRange.MaximumFrequencyInkHz
);
BaseClockInkHz = new GPUPerformanceStateValueRange(
CurrentClockInkHz.Minimum - ClockDeltaInkHz,
CurrentClockInkHz.Maximum - ClockDeltaInkHz
);
DependentVoltageDomain = states20ClockEntry.FrequencyRange.VoltageDomainId;
DependentVoltageRangeInMicroVolt = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyRange.MinimumVoltageInMicroVolt,
states20ClockEntry.FrequencyRange.MaximumVoltageInMicroVolt
);
}
else
{
CurrentClockInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.SingleFrequency.FrequencyInkHz
);
BaseClockInkHz = new GPUPerformanceStateValueRange(
CurrentClockInkHz.Minimum - ClockDeltaInkHz
);
DependentVoltageDomain = PerformanceVoltageDomain.Undefined;
DependentVoltageRangeInMicroVolt = null;
}
}
/// <summary>
/// Gets the base clock frequency in kHz
/// </summary>
public GPUPerformanceStateValueRange BaseClockInkHz { get; }
/// <summary>
/// Gets the clock frequency delta in kHz
/// </summary>
public int ClockDeltaInkHz { get; }
/// <summary>
/// Gets the clock frequency delta range in kHz
/// </summary>
public GPUPerformanceStateValueRange ClockDeltaRangeInkHz { get; }
/// <summary>
/// Gets the clock domain
/// </summary>
public PublicClockDomain ClockDomain { get; }
/// <summary>
/// Gets the current clock frequency in kHz
/// </summary>
public GPUPerformanceStateValueRange CurrentClockInkHz { get; }
/// <summary>
/// Gets the dependent voltage domain
/// </summary>
public PerformanceVoltageDomain DependentVoltageDomain { get; }
/// <summary>
/// Gets the dependent voltage range in uV
/// </summary>
public GPUPerformanceStateValueRange DependentVoltageRangeInMicroVolt { get; }
/// <summary>
/// Gets a boolean value indicating if this clock setting is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <inheritdoc />
public override string ToString()
{
var title = IsReadOnly ? $"{ClockDomain} (ReadOnly)" : ClockDomain.ToString();
return
$"{title}: {BaseClockInkHz} + ({ClockDeltaInkHz}) = {CurrentClockInkHz}";
}
}
}

View File

@@ -0,0 +1,115 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents an integer value range
/// </summary>
public class GPUPerformanceStateValueRange : IEquatable<GPUPerformanceStateValueRange>
{
/// <summary>
/// Creates a new instance of <see cref="GPUPerformanceStateValueRange" />.
/// </summary>
/// <param name="min">The lower bound of the range.</param>
/// <param name="max">The upper bound of the range.</param>
public GPUPerformanceStateValueRange(long min, long max)
{
Minimum = min;
Maximum = max;
}
/// <summary>
/// Creates a new single value instance of <see cref="GPUPerformanceStateValueRange" />.
/// </summary>
/// <param name="value">The only value in the range</param>
public GPUPerformanceStateValueRange(long value)
{
Minimum = value;
Maximum = value;
}
/// <summary>
/// Gets the upper bound of the inclusive range
/// </summary>
public long Maximum { get; }
/// <summary>
/// Gets the lower bound of the inclusive range
/// </summary>
public long Minimum { get; }
/// <inheritdoc />
public bool Equals(GPUPerformanceStateValueRange other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Maximum == other.Maximum && Minimum == other.Minimum;
}
/// <summary>
/// Checks two instances of <see cref="GPUPerformanceStateValueRange" /> for equality.
/// </summary>
/// <param name="left">The left side of the comparison.</param>
/// <param name="right">The right side of the comparison.</param>
/// <returns>true if instances are equal, otherwise false</returns>
public static bool operator ==(GPUPerformanceStateValueRange left, GPUPerformanceStateValueRange right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Checks two instances of <see cref="GPUPerformanceStateValueRange" /> for inequality.
/// </summary>
/// <param name="left">The left side of the comparison.</param>
/// <param name="right">The right side of the comparison.</param>
/// <returns>true if instances are in-equal, otherwise false</returns>
public static bool operator !=(GPUPerformanceStateValueRange left, GPUPerformanceStateValueRange right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as GPUPerformanceStateValueRange);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
return ((int) Maximum * 397) ^ (int) Minimum;
}
}
/// <inheritdoc />
public override string ToString()
{
if (Minimum == Maximum)
{
return $"({Minimum})";
}
return $"[({Minimum}) - ({Maximum})]";
}
}
}

View File

@@ -0,0 +1,65 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state voltage settings
/// </summary>
public class GPUPerformanceStateVoltage
{
internal GPUPerformanceStateVoltage(IPerformanceStates20VoltageEntry states20BaseVoltageEntry)
{
VoltageDomain = states20BaseVoltageEntry.DomainId;
IsReadOnly = !states20BaseVoltageEntry.IsEditable;
CurrentVoltageInMicroVolt = states20BaseVoltageEntry.ValueInMicroVolt;
VoltageDeltaInMicroVolt = states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaValue;
BaseVoltageInMicroVolt = (int) (CurrentVoltageInMicroVolt - VoltageDeltaInMicroVolt);
VoltageDeltaRangeInMicroVolt = new GPUPerformanceStateValueRange(
states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaRange.Minimum,
states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaRange.Maximum
);
}
/// <summary>
/// Gets the base voltage in uV
/// </summary>
public int BaseVoltageInMicroVolt { get; }
/// <summary>
/// Gets the current voltage in uV
/// </summary>
public uint CurrentVoltageInMicroVolt { get; }
/// <summary>
/// Gets a boolean value indicating if this voltage is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets the voltage delta in uV
/// </summary>
public int VoltageDeltaInMicroVolt { get; }
/// <summary>
/// Gets the voltage delta range in uV
/// </summary>
public GPUPerformanceStateValueRange VoltageDeltaRangeInMicroVolt { get; }
/// <summary>
/// Gets the voltage domain
/// </summary>
public PerformanceVoltageDomain VoltageDomain { get; }
/// <inheritdoc />
public override string ToString()
{
var title = IsReadOnly ? $"{VoltageDomain} (ReadOnly)" : VoltageDomain.ToString();
return
$"{title}: ({BaseVoltageInMicroVolt}) + ({VoltageDeltaInMicroVolt}) = ({CurrentVoltageInMicroVolt})";
}
}
}

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds the retrieved performance states information
/// </summary>
public class GPUPerformanceStatesInformation
{
internal GPUPerformanceStatesInformation(
IPerformanceStates20Info states20Info,
PerformanceStateId currentPerformanceStateId,
PrivatePCIeInfoV2? pciInformation)
{
IsReadOnly = !states20Info.IsEditable;
GlobalVoltages = states20Info.GeneralVoltages
.Select(entry => new GPUPerformanceStateVoltage(entry))
.ToArray();
var clocks = states20Info.Clocks;
var baseVoltages = states20Info.Voltages;
PerformanceStates = states20Info.PerformanceStates.Select((state20, i) =>
{
PCIeInformation statePCIeInfo = null;
if (pciInformation != null && pciInformation.Value.PCIePerformanceStateInfos.Length > i)
{
statePCIeInfo = new PCIeInformation(pciInformation.Value.PCIePerformanceStateInfos[i]);
}
return new GPUPerformanceState(
i,
state20,
clocks[state20.StateId],
baseVoltages[state20.StateId],
statePCIeInfo
);
}).ToArray();
CurrentPerformanceState =
PerformanceStates.FirstOrDefault(performanceState =>
performanceState.StateId == currentPerformanceStateId);
}
/// <summary>
/// Gets the currently active performance state
/// </summary>
public GPUPerformanceState CurrentPerformanceState { get; }
/// <summary>
/// Gets a list of global voltage settings
/// </summary>
public GPUPerformanceStateVoltage[] GlobalVoltages { get; }
/// <summary>
/// Gets a boolean value indicating if performance states are readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets a list of all available performance states
/// </summary>
public GPUPerformanceState[] PerformanceStates { get; }
/// <inheritdoc />
public override string ToString()
{
if (PerformanceStates.Length == 0)
{
return "No Performance State Available";
}
return string.Join(
", ",
PerformanceStates
.Select(
state =>
{
var attributes = new List<string>();
if (state.IsReadOnly)
{
attributes.Add("ReadOnly");
}
if (CurrentPerformanceState.StateId == state.StateId)
{
attributes.Add("Active");
}
if (attributes.Any())
{
return $"{state.StateId} ({string.Join(" - ", attributes)})";
}
return state.StateId.ToString();
})
);
}
}
}

View File

@@ -0,0 +1,70 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a possible power limit policy and its acceptable range
/// </summary>
public class GPUPowerLimitInfo
{
internal GPUPowerLimitInfo(PrivatePowerPoliciesInfoV1.PowerPolicyInfoEntry powerPolicyInfoEntry)
{
PerformanceStateId = powerPolicyInfoEntry.PerformanceStateId;
MinimumPowerInPCM = powerPolicyInfoEntry.MinimumPowerInPCM;
DefaultPowerInPCM = powerPolicyInfoEntry.DefaultPowerInPCM;
MaximumPowerInPCM = powerPolicyInfoEntry.MaximumPowerInPCM;
}
/// <summary>
/// Gets the default policy target power in per cent mille (PCM)
/// </summary>
public uint DefaultPowerInPCM { get; }
/// <summary>
/// Gets the default policy target power in percentage
/// </summary>
public float DefaultPowerInPercent
{
get => DefaultPowerInPCM / 1000f;
}
/// <summary>
/// Gets the maximum possible policy target power in per cent mille (PCM)
/// </summary>
public uint MaximumPowerInPCM { get; }
/// <summary>
/// Gets the maximum possible policy target power in percentage
/// </summary>
public float MaximumPowerInPercent
{
get => MaximumPowerInPCM / 1000f;
}
/// <summary>
/// Gets the minimum possible policy target power in per cent mille (PCM)
/// </summary>
public uint MinimumPowerInPCM { get; }
/// <summary>
/// Gets the minimum possible policy target power in percentage
/// </summary>
public float MinimumPowerInPercent
{
get => MinimumPowerInPCM / 1000f;
}
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{PerformanceStateId}] Default: {DefaultPowerInPercent}% - Range: ({MinimumPowerInPercent}% - {MaximumPowerInPercent}%)";
}
}
}

View File

@@ -0,0 +1,41 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a currently active power limit policy
/// </summary>
public class GPUPowerLimitPolicy
{
internal GPUPowerLimitPolicy(PrivatePowerPoliciesStatusV1.PowerPolicyStatusEntry powerPolicyStatusEntry)
{
PerformanceStateId = powerPolicyStatusEntry.PerformanceStateId;
PowerTargetInPCM = powerPolicyStatusEntry.PowerTargetInPCM;
}
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <summary>
/// Gets the current policy target power in per cent mille (PCM)
/// </summary>
public uint PowerTargetInPCM { get; }
/// <summary>
/// Gets the current policy target power in percentage
/// </summary>
public float PowerTargetInPercent
{
get => PowerTargetInPCM / 1000f;
}
/// <inheritdoc />
public override string ToString()
{
return $"{PerformanceStateId} Target: {PowerTargetInPercent}%";
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding current power topology and their current power usage
/// </summary>
public class GPUPowerTopologyInformation
{
internal GPUPowerTopologyInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the current power topology entries
/// </summary>
public IEnumerable<GPUPowerTopologyStatus> PowerTopologyEntries
{
get
{
return GPUApi.ClientPowerTopologyGetStatus(PhysicalGPU.Handle).PowerPolicyStatusEntries
.Select(entry => new GPUPowerTopologyStatus(entry));
}
}
}
}

View File

@@ -0,0 +1,42 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about a power domain usage
/// </summary>
public class GPUPowerTopologyStatus
{
internal GPUPowerTopologyStatus(
PrivatePowerTopologiesStatusV1.PowerTopologiesStatusEntry powerTopologiesStatusEntry)
{
Domain = powerTopologiesStatusEntry.Domain;
PowerUsageInPCM = powerTopologiesStatusEntry.PowerUsageInPCM;
}
/// <summary>
/// Gets the power usage domain
/// </summary>
public PowerTopologyDomain Domain { get; }
/// <summary>
/// Gets the current power usage in per cent mille (PCM)
/// </summary>
public uint PowerUsageInPCM { get; }
/// <summary>
/// Gets the current power usage in percentage
/// </summary>
public float PowerUsageInPercent
{
get => PowerUsageInPCM / 1000f;
}
/// <inheritdoc />
public override string ToString()
{
return $"[{Domain}] {PowerUsageInPercent}%";
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding the available thermal sensors and current thermal level of a GPU
/// </summary>
public class GPUThermalInformation
{
internal GPUThermalInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the current thermal level of the GPU
/// </summary>
public int CurrentThermalLevel
{
get => (int) GPUApi.GetCurrentThermalLevel(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the list of available thermal sensors
/// </summary>
public IEnumerable<GPUThermalSensor> ThermalSensors
{
get
{
return GPUApi.GetThermalSettings(PhysicalGPU.Handle).Sensors
.Select((sensor, i) => new GPUThermalSensor(i, sensor));
}
}
}
}

View File

@@ -0,0 +1,47 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a possible thermal limit policy and its acceptable range
/// </summary>
public class GPUThermalLimitInfo
{
internal GPUThermalLimitInfo(PrivateThermalPoliciesInfoV2.ThermalPoliciesInfoEntry policiesInfoEntry)
{
Controller = policiesInfoEntry.Controller;
MinimumTemperature = policiesInfoEntry.MinimumTemperature;
DefaultTemperature = policiesInfoEntry.DefaultTemperature;
MaximumTemperature = policiesInfoEntry.MaximumTemperature;
}
/// <summary>
/// Gets the policy's thermal controller
/// </summary>
public ThermalController Controller { get; }
/// <summary>
/// Gets the default policy target temperature in degree Celsius
/// </summary>
public int DefaultTemperature { get; }
/// <summary>
/// Gets the maximum possible policy target temperature in degree Celsius
/// </summary>
public int MaximumTemperature { get; }
/// <summary>
/// Gets the minimum possible policy target temperature in degree Celsius
/// </summary>
public int MinimumTemperature { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{Controller}] Default: {DefaultTemperature}°C - Range: ({MinimumTemperature}°C - {MaximumTemperature}°C)";
}
}
}

View File

@@ -0,0 +1,40 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a currently active temperature limit policy
/// </summary>
public class GPUThermalLimitPolicy
{
internal GPUThermalLimitPolicy(PrivateThermalPoliciesStatusV2.ThermalPoliciesStatusEntry thermalPoliciesEntry)
{
Controller = thermalPoliciesEntry.Controller;
PerformanceStateId = thermalPoliciesEntry.PerformanceStateId;
TargetTemperature = thermalPoliciesEntry.TargetTemperature;
}
/// <summary>
/// Gets the policy's thermal controller
/// </summary>
public ThermalController Controller { get; }
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <summary>
/// Gets the current policy target temperature in degree Celsius
/// </summary>
public int TargetTemperature { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"{PerformanceStateId} [{Controller}] Target: {TargetTemperature}°C";
}
}
}

View File

@@ -0,0 +1,48 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a thermal sensor
/// </summary>
public class GPUThermalSensor : IThermalSensor
{
internal GPUThermalSensor(int sensorId, IThermalSensor thermalSensor)
{
SensorId = sensorId;
Controller = thermalSensor.Controller;
DefaultMinimumTemperature = thermalSensor.DefaultMinimumTemperature;
DefaultMaximumTemperature = thermalSensor.DefaultMaximumTemperature;
CurrentTemperature = thermalSensor.CurrentTemperature;
Target = thermalSensor.Target;
}
/// <summary>
/// Gets the sensor identification number or index
/// </summary>
public int SensorId { get; set; }
/// <inheritdoc />
public ThermalController Controller { get; }
/// <inheritdoc />
public int CurrentTemperature { get; }
/// <inheritdoc />
public int DefaultMaximumTemperature { get; }
/// <inheritdoc />
public int DefaultMinimumTemperature { get; }
/// <inheritdoc />
public ThermalSettingsTarget Target { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{Target} @ {Controller}] Current: {CurrentTemperature}°C - Default Range: [({DefaultMinimumTemperature}°C) , ({DefaultMaximumTemperature}°C)]";
}
}
}

View File

@@ -0,0 +1,33 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information about a utilization domain
/// </summary>
public class GPUUsageDomainStatus
{
internal GPUUsageDomainStatus(UtilizationDomain domain, IUtilizationDomainInfo utilizationDomainInfo)
{
Domain = domain;
Percentage = (int) utilizationDomainInfo.Percentage;
}
/// <summary>
/// Gets the utilization domain that this instance describes
/// </summary>
public UtilizationDomain Domain { get; }
/// <summary>
/// Gets the percentage of time where the domain is considered busy in the last 1 second interval.
/// </summary>
public int Percentage { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{Domain}] {Percentage}%";
}
}
}

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information about the GPU utilization domains
/// </summary>
public class GPUUsageInformation
{
internal GPUUsageInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the Bus interface (BUS) utilization
/// </summary>
public GPUUsageDomainStatus BusInterface
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.BusInterface);
}
/// <summary>
/// Gets the frame buffer (FB) utilization
/// </summary>
public GPUUsageDomainStatus FrameBuffer
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.FrameBuffer);
}
/// <summary>
/// Gets the graphic engine (GPU) utilization
/// </summary>
public GPUUsageDomainStatus GPU
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.GPU);
}
/// <summary>
/// Gets a boolean value indicating if the dynamic performance states is enabled
/// </summary>
public bool IsDynamicPerformanceStatesEnabled
{
get => GPUApi.GetDynamicPerformanceStatesInfoEx(PhysicalGPU.Handle).IsDynamicPerformanceStatesEnabled;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets all valid utilization domains and information
/// </summary>
public IEnumerable<GPUUsageDomainStatus> UtilizationDomainsStatus
{
get
{
try
{
var dynamicPerformanceStates = GPUApi.GetDynamicPerformanceStatesInfoEx(PhysicalGPU.Handle);
if (dynamicPerformanceStates.IsDynamicPerformanceStatesEnabled)
{
return dynamicPerformanceStates.Domains
.Select(pair => new GPUUsageDomainStatus(pair.Key, pair.Value));
}
}
catch
{
// ignored
}
return GPUApi.GetUsages(PhysicalGPU.Handle).Domains
.Select(pair => new GPUUsageDomainStatus(pair.Key, pair.Value));
}
}
/// <summary>
/// Gets the Video engine (VID) utilization
/// </summary>
public GPUUsageDomainStatus VideoEngine
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.VideoEngine);
}
/// <summary>
/// Enables dynamic performance states
/// </summary>
public void EnableDynamicPerformanceStates()
{
GPUApi.EnableDynamicPStates(PhysicalGPU.Handle);
}
}
}

View File

@@ -0,0 +1,119 @@
using System;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a logical NVIDIA GPU
/// </summary>
public class LogicalGPU : IEquatable<LogicalGPU>
{
/// <summary>
/// Creates a new LogicalGPU
/// </summary>
/// <param name="handle">Logical GPU handle</param>
public LogicalGPU(LogicalGPUHandle handle)
{
Handle = handle;
}
/// <summary>
/// Gets a list of all corresponding physical GPUs
/// </summary>
public PhysicalGPU[] CorrespondingPhysicalGPUs
{
get
{
return GPUApi.GetPhysicalGPUsFromLogicalGPU(Handle).Select(handle => new PhysicalGPU(handle)).ToArray();
}
}
/// <summary>
/// Gets the logical GPU handle
/// </summary>
public LogicalGPUHandle Handle { get; }
/// <inheritdoc />
public bool Equals(LogicalGPU other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// Gets all logical GPUs
/// </summary>
/// <returns>An array of logical GPUs</returns>
public static LogicalGPU[] GetLogicalGPUs()
{
return GPUApi.EnumLogicalGPUs().Select(handle => new LogicalGPU(handle)).ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(LogicalGPU left, LogicalGPU right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(LogicalGPU left, LogicalGPU right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((LogicalGPU) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return
$"Logical GPU [{CorrespondingPhysicalGPUs.Length}] {{{string.Join(", ", CorrespondingPhysicalGPUs.Select(gpu => gpu.FullName).ToArray())}}}";
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the PCI connection
/// </summary>
public class PCIIdentifiers : IEquatable<PCIIdentifiers>
{
// ReSharper disable once TooManyDependencies
internal PCIIdentifiers(uint deviceId, uint subSystemId, uint revisionId, int externalDeviceId = 0)
{
DeviceId = deviceId;
SubSystemId = subSystemId;
RevisionId = revisionId;
if (externalDeviceId > 0)
{
ExternalDeviceId = (ushort) externalDeviceId;
}
else
{
ExternalDeviceId = (ushort) (deviceId >> 16);
}
VendorId = (ushort) ((DeviceId << 16) >> 16);
}
/// <summary>
/// Gets the internal PCI device identifier
/// </summary>
public uint DeviceId { get; }
/// <summary>
/// Gets the external PCI device identifier
/// </summary>
public ushort ExternalDeviceId { get; }
/// <summary>
/// Gets the internal PCI device-specific revision identifier
/// </summary>
public uint RevisionId { get; }
/// <summary>
/// Gets the internal PCI subsystem identifier
/// </summary>
public uint SubSystemId { get; }
/// <summary>
/// Gets the vendor identification calculated from internal device identification
/// </summary>
public ushort VendorId { get; }
/// <inheritdoc />
public bool Equals(PCIIdentifiers other)
{
return DeviceId == other.DeviceId &&
SubSystemId == other.SubSystemId &&
RevisionId == other.RevisionId;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PCIIdentifiers left, PCIIdentifiers right)
{
return left.Equals(right);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PCIIdentifiers left, PCIIdentifiers right)
{
return !left.Equals(right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is PCIIdentifiers identifiers && Equals(identifiers);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) DeviceId;
hashCode = (hashCode * 397) ^ (int) SubSystemId;
hashCode = (hashCode * 397) ^ (int) RevisionId;
return hashCode;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"PCI\\VEN_{VendorId:X}&DEV_{ExternalDeviceId:X}&SUBSYS_{SubSystemId:X}&REV_{RevisionId:X}";
}
}
}

View File

@@ -0,0 +1,67 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the PCI-e connection
/// </summary>
public class PCIeInformation
{
internal PCIeInformation(PrivatePCIeInfoV2.PCIePerformanceStateInfo stateInfo)
{
TransferRateInMTps = stateInfo.TransferRateInMTps;
Generation = stateInfo.Generation;
Lanes = stateInfo.Lanes;
Version = stateInfo.Version;
}
/// <summary>
/// Gets the PCI-e generation
/// </summary>
public PCIeGeneration Generation { get; }
/// <summary>
/// Gets the PCI-e down stream lanes
/// </summary>
public uint Lanes { get; }
/// <summary>
/// Gets the PCIe transfer rate in Mega Transfers per Second
/// </summary>
public uint TransferRateInMTps { get; }
/// <summary>
/// Gets the PCI-e version
/// </summary>
public PCIeGeneration Version { get; }
/// <inheritdoc />
public override string ToString()
{
var v = "Unknown";
switch (Version)
{
case PCIeGeneration.PCIe1:
v = "PCIe 1.0";
break;
case PCIeGeneration.PCIe1Minor1:
v = "PCIe 1.1";
break;
case PCIeGeneration.PCIe2:
v = "PCIe 2.0";
break;
case PCIeGeneration.PCIe3:
v = "PCIe 3.0";
break;
}
return $"{v} x{Lanes} - {TransferRateInMTps} MTps";
}
}
}

View File

@@ -0,0 +1,559 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a physical NVIDIA GPU
/// </summary>
public class PhysicalGPU : IEquatable<PhysicalGPU>
{
/// <summary>
/// Creates a new PhysicalGPU
/// </summary>
/// <param name="handle">Physical GPU handle</param>
public PhysicalGPU(PhysicalGPUHandle handle)
{
Handle = handle;
UsageInformation = new GPUUsageInformation(this);
ThermalInformation = new GPUThermalInformation(this);
BusInformation = new GPUBusInformation(this);
ArchitectInformation = new GPUArchitectInformation(this);
MemoryInformation = new GPUMemoryInformation(this);
CoolerInformation = new GPUCoolerInformation(this);
ECCMemoryInformation = new ECCMemoryInformation(this);
PerformanceControl = new GPUPerformanceControl(this);
PowerTopologyInformation = new GPUPowerTopologyInformation(this);
}
/// <summary>
/// Gets all active outputs of this GPU
/// </summary>
public GPUOutput[] ActiveOutputs
{
get
{
var outputs = new List<GPUOutput>();
var allOutputs = GPUApi.GetActiveOutputs(Handle);
foreach (OutputId outputId in Enum.GetValues(typeof(OutputId)))
{
if (outputId != OutputId.Invalid && allOutputs.HasFlag(outputId))
{
outputs.Add(new GPUOutput(outputId, this));
}
}
return outputs.ToArray();
}
}
/// <summary>
/// Gets GPU architect information
/// </summary>
public GPUArchitectInformation ArchitectInformation { get; }
/// <summary>
/// Gets GPU base clock frequencies
/// </summary>
public IClockFrequencies BaseClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BaseClock));
}
/// <summary>
/// Gets GPU video BIOS information
/// </summary>
public VideoBIOS Bios
{
get => new VideoBIOS(
GPUApi.GetVBIOSRevision(Handle),
(int) GPUApi.GetVBIOSOEMRevision(Handle),
GPUApi.GetVBIOSVersionString(Handle)
);
}
/// <summary>
/// Gets the board information
/// </summary>
public BoardInfo Board
{
get
{
try
{
return GPUApi.GetBoardInfo(Handle);
}
catch (NVIDIAApiException ex)
{
if (ex.Status == Status.NotSupported)
{
return default;
}
throw;
}
}
}
/// <summary>
/// Gets GPU boost clock frequencies
/// </summary>
public IClockFrequencies BoostClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BoostClock));
}
/// <summary>
/// Gets GPU bus information
/// </summary>
public GPUBusInformation BusInformation { get; }
/// <summary>
/// Gets GPU coolers information
/// </summary>
public GPUCoolerInformation CoolerInformation { get; }
/// <summary>
/// Gets corresponding logical GPU
/// </summary>
public LogicalGPU CorrespondingLogicalGPU
{
get => new LogicalGPU(GPUApi.GetLogicalGPUFromPhysicalGPU(Handle));
}
/// <summary>
/// Gets GPU current clock frequencies
/// </summary>
public IClockFrequencies CurrentClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.CurrentClock));
}
/// <summary>
/// Gets the driver model number for this GPU
/// </summary>
public uint DriverModel
{
get => GPUApi.GetDriverModel(Handle);
}
/// <summary>
/// Gets GPU ECC memory information
/// </summary>
public ECCMemoryInformation ECCMemoryInformation { get; }
/// <summary>
/// Gets the chipset foundry
/// </summary>
public GPUFoundry Foundry
{
get => GPUApi.GetFoundry(Handle);
}
/// <summary>
/// Gets GPU full name
/// </summary>
public string FullName
{
get => GPUApi.GetFullName(Handle);
}
/// <summary>
/// Gets the GPU identification number
/// </summary>
public uint GPUId
{
get => GPUApi.GetGPUIDFromPhysicalGPU(Handle);
}
/// <summary>
/// Gets GPU type
/// </summary>
public GPUType GPUType
{
get => GPUApi.GetGPUType(Handle);
}
/// <summary>
/// Gets the physical GPU handle
/// </summary>
public PhysicalGPUHandle Handle { get; }
/// <summary>
/// Gets a boolean value indicating the Quadro line of products
/// </summary>
public bool IsQuadro
{
get => GPUApi.GetQuadroStatus(Handle);
}
/// <summary>
/// Gets GPU memory and RAM information as well as frame-buffer information
/// </summary>
public GPUMemoryInformation MemoryInformation { get; }
/// <summary>
/// Gets GPU performance control status and configurations
/// </summary>
public GPUPerformanceControl PerformanceControl { get; }
/// <summary>
/// Gets the GPU performance states information and configurations
/// </summary>
public GPUPerformanceStatesInformation PerformanceStatesInfo
{
get
{
var performanceStates20Info = GPUApi.GetPerformanceStates20(Handle);
var currentPerformanceState = GPUApi.GetCurrentPerformanceState(Handle);
PrivatePCIeInfoV2? pcieInformation = null;
if (BusInformation.BusType == GPUBusType.PCIExpress)
{
try
{
pcieInformation = GPUApi.GetPCIEInfo(Handle);
}
catch
{
// ignore
}
}
return new GPUPerformanceStatesInformation(performanceStates20Info, currentPerformanceState,
pcieInformation);
}
}
/// <summary>
/// Gets GPU coolers information
/// </summary>
public GPUPowerTopologyInformation PowerTopologyInformation { get; }
/// <summary>
/// Gets GPU system type
/// </summary>
public SystemType SystemType
{
get => GPUApi.GetSystemType(Handle);
}
/// <summary>
/// Gets GPU thermal sensors information
/// </summary>
public GPUThermalInformation ThermalInformation { get; }
/// <summary>
/// Gets the GPU utilization domains and usages
/// </summary>
public GPUUsageInformation UsageInformation { get; }
/// <inheritdoc />
public bool Equals(PhysicalGPU other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// Gets the corresponding <see cref="PhysicalGPU" /> instance from a GPU identification number.
/// </summary>
/// <param name="gpuId">The GPU identification number.</param>
/// <returns>An instance of <see cref="PhysicalGPU" /> or <see langword="null" /> if operation failed.</returns>
public static PhysicalGPU FromGPUId(uint gpuId)
{
var handle = GPUApi.GetPhysicalGPUFromGPUID(gpuId);
if (handle.IsNull)
{
return null;
}
return new PhysicalGPU(handle);
}
/// <summary>
/// Gets all physical GPUs
/// </summary>
/// <returns>An array of physical GPUs</returns>
public static PhysicalGPU[] GetPhysicalGPUs()
{
return GPUApi.EnumPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
/// <summary>
/// Gets all physical GPUs in TCC state
/// </summary>
/// <returns>An array of physical GPUs</returns>
public static PhysicalGPU[] GetTCCPhysicalGPUs()
{
return GPUApi.EnumTCCPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PhysicalGPU left, PhysicalGPU right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PhysicalGPU left, PhysicalGPU right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as PhysicalGPU);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return FullName;
}
/// <summary>
/// Get a list of all active applications for this GPU
/// </summary>
/// <returns>An array of processes</returns>
public Process[] GetActiveApplications()
{
return GPUApi.QueryActiveApps(Handle).Select(app => Process.GetProcessById(app.ProcessId)).ToArray();
}
/// <summary>
/// Get a list of all connected display devices on this GPU
/// </summary>
/// <param name="flags">ConnectedIdsFlag flag</param>
/// <returns>An array of display devices</returns>
public DisplayDevice[] GetConnectedDisplayDevices(ConnectedIdsFlag flags)
{
return GPUApi.GetConnectedDisplayIds(Handle, flags).Select(display => new DisplayDevice(display)).ToArray();
}
/// <summary>
/// Get the display device connected to a specific GPU output
/// </summary>
/// <param name="output">The GPU output to get connected display device for</param>
/// <returns>DisplayDevice connected to the specified GPU output</returns>
public DisplayDevice GetDisplayDeviceByOutput(GPUOutput output)
{
return new DisplayDevice(GPUApi.GetDisplayIdFromGPUAndOutputId(Handle, output.OutputId));
}
/// <summary>
/// Get a list of all display devices on any possible output
/// </summary>
/// <returns>An array of display devices</returns>
public DisplayDevice[] GetDisplayDevices()
{
return GPUApi.GetAllDisplayIds(Handle).Select(display => new DisplayDevice(display)).ToArray();
}
/// <summary>
/// Reads EDID data of an output
/// </summary>
/// <param name="output">The GPU output to read EDID information for</param>
/// <returns>A byte array containing EDID data</returns>
public byte[] ReadEDIDData(GPUOutput output)
{
try
{
var data = new byte[0];
var identification = 0;
var totalSize = EDIDV3.MaxDataSize;
for (var offset = 0; offset < totalSize; offset += EDIDV3.MaxDataSize)
{
var edid = GPUApi.GetEDID(Handle, output.OutputId, offset, identification);
identification = edid.Identification;
totalSize = edid.TotalSize;
var edidData = edid.Data;
Array.Resize(ref data, data.Length + edidData.Length);
Array.Copy(edidData, 0, data, data.Length - edidData.Length, edidData.Length);
}
return data;
}
catch (NVIDIAApiException ex)
{
if (ex.Status == Status.IncompatibleStructureVersion)
{
return GPUApi.GetEDID(Handle, output.OutputId).Data;
}
throw;
}
}
/// <summary>
/// Reads data from the I2C bus
/// </summary>
/// <param name="i2cInfo">Information required to read from the I2C bus.</param>
/// <returns>The returned payload.</returns>
// ReSharper disable once InconsistentNaming
public byte[] ReadI2C(II2CInfo i2cInfo)
{
GPUApi.I2CRead(Handle, ref i2cInfo);
return i2cInfo.Data;
}
/// <summary>
/// Validates a set of GPU outputs to check if they can be active simultaneously
/// </summary>
/// <param name="outputs">GPU outputs to check</param>
/// <returns>true if all specified outputs can be active simultaneously, otherwise false</returns>
public bool ValidateOutputCombination(GPUOutput[] outputs)
{
var gpuOutpudIds =
outputs.Aggregate(OutputId.Invalid, (current, gpuOutput) => current | gpuOutput.OutputId);
return GPUApi.ValidateOutputCombination(Handle, gpuOutpudIds);
}
/// <summary>
/// Writes EDID data of an output
/// </summary>
/// <param name="output">The GPU output to write EDID information for</param>
/// <param name="edidData">A byte array containing EDID data</param>
public void WriteEDIDData(GPUOutput output, byte[] edidData)
{
WriteEDIDData((uint) output.OutputId, edidData);
}
/// <summary>
/// Writes EDID data of an display
/// </summary>
/// <param name="display">The display device to write EDID information for</param>
/// <param name="edidData">A byte array containing EDID data</param>
public void WriteEDIDData(DisplayDevice display, byte[] edidData)
{
WriteEDIDData(display.DisplayId, edidData);
}
/// <summary>
/// Writes data to the I2C bus
/// </summary>
/// <param name="i2cInfo">Information required to write to the I2C bus including data payload.</param>
// ReSharper disable once InconsistentNaming
public void WriteI2C(II2CInfo i2cInfo)
{
GPUApi.I2CWrite(Handle, i2cInfo);
}
private void WriteEDIDData(uint displayOutputId, byte[] edidData)
{
try
{
if (edidData.Length == 0)
{
var instance = typeof(EDIDV3).Instantiate<EDIDV3>();
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
for (var offset = 0; offset < edidData.Length; offset += EDIDV3.MaxDataSize)
{
var array = new byte[Math.Min(EDIDV3.MaxDataSize, edidData.Length - offset)];
Array.Copy(edidData, offset, array, 0, array.Length);
var instance = EDIDV3.CreateWithData(0, (uint) offset, array, edidData.Length);
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
return;
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
try
{
if (edidData.Length == 0)
{
var instance = typeof(EDIDV2).Instantiate<EDIDV2>();
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
for (var offset = 0; offset < edidData.Length; offset += EDIDV2.MaxDataSize)
{
var array = new byte[Math.Min(EDIDV2.MaxDataSize, edidData.Length - offset)];
Array.Copy(edidData, offset, array, 0, array.Length);
GPUApi.SetEDID(Handle, displayOutputId, EDIDV2.CreateWithData(array, edidData.Length));
}
return;
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
GPUApi.SetEDID(Handle, displayOutputId, EDIDV1.CreateWithData(edidData));
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU Video BIOS
/// </summary>
public class VideoBIOS
{
internal VideoBIOS(uint revision, int oemRevision, string versionString)
{
Revision = revision;
OEMRevision = oemRevision;
VersionString = versionString.ToUpper();
}
/// <summary>
/// Gets the the OEM revision of the video BIOS
/// </summary>
public int OEMRevision { get; }
/// <summary>
/// Gets the revision of the video BIOS
/// </summary>
public uint Revision { get; }
/// <summary>
/// Gets the full video BIOS version string
/// </summary>
public string VersionString { get; }
/// <inheritdoc />
public override string ToString()
{
return AsVersion().ToString();
}
/// <summary>
/// Returns the video BIOS version as a .Net Version object
/// </summary>
/// <returns>A Version object representing the video BIOS version</returns>
public Version AsVersion()
{
return new Version(
(int) ((Revision >> 28) + ((Revision << 4) >> 28) * 16), // 8 bit little endian
(int) (((Revision << 8) >> 28) + ((Revision << 12) >> 28) * 16), // 8 bit little endian
(int) ((Revision << 16) >> 16), // 16 bit big endian
OEMRevision // 8 bit integer
);
}
}
}