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
{
///
/// Represents a physical NVIDIA GPU
///
public class PhysicalGPU : IEquatable
{
///
/// Creates a new PhysicalGPU
///
/// Physical GPU handle
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);
}
///
/// Gets all active outputs of this GPU
///
public GPUOutput[] ActiveOutputs
{
get
{
var outputs = new List();
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();
}
}
///
/// Gets GPU architect information
///
public GPUArchitectInformation ArchitectInformation { get; }
///
/// Gets GPU base clock frequencies
///
public IClockFrequencies BaseClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BaseClock));
}
///
/// Gets GPU video BIOS information
///
public VideoBIOS Bios
{
get => new VideoBIOS(
GPUApi.GetVBIOSRevision(Handle),
(int) GPUApi.GetVBIOSOEMRevision(Handle),
GPUApi.GetVBIOSVersionString(Handle)
);
}
///
/// Gets the board information
///
public BoardInfo Board
{
get
{
try
{
return GPUApi.GetBoardInfo(Handle);
}
catch (NVIDIAApiException ex)
{
if (ex.Status == Status.NotSupported)
{
return default;
}
throw;
}
}
}
///
/// Gets GPU boost clock frequencies
///
public IClockFrequencies BoostClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BoostClock));
}
///
/// Gets GPU bus information
///
public GPUBusInformation BusInformation { get; }
///
/// Gets GPU coolers information
///
public GPUCoolerInformation CoolerInformation { get; }
///
/// Gets corresponding logical GPU
///
public LogicalGPU CorrespondingLogicalGPU
{
get => new LogicalGPU(GPUApi.GetLogicalGPUFromPhysicalGPU(Handle));
}
///
/// Gets GPU current clock frequencies
///
public IClockFrequencies CurrentClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.CurrentClock));
}
///
/// Gets the driver model number for this GPU
///
public uint DriverModel
{
get => GPUApi.GetDriverModel(Handle);
}
///
/// Gets GPU ECC memory information
///
public ECCMemoryInformation ECCMemoryInformation { get; }
///
/// Gets the chipset foundry
///
public GPUFoundry Foundry
{
get => GPUApi.GetFoundry(Handle);
}
///
/// Gets GPU full name
///
public string FullName
{
get => GPUApi.GetFullName(Handle);
}
///
/// Gets the GPU identification number
///
public uint GPUId
{
get => GPUApi.GetGPUIDFromPhysicalGPU(Handle);
}
///
/// Gets GPU type
///
public GPUType GPUType
{
get => GPUApi.GetGPUType(Handle);
}
///
/// Gets the physical GPU handle
///
public PhysicalGPUHandle Handle { get; }
///
/// Gets a boolean value indicating the Quadro line of products
///
public bool IsQuadro
{
get => GPUApi.GetQuadroStatus(Handle);
}
///
/// Gets GPU memory and RAM information as well as frame-buffer information
///
public GPUMemoryInformation MemoryInformation { get; }
///
/// Gets GPU performance control status and configurations
///
public GPUPerformanceControl PerformanceControl { get; }
///
/// Gets the GPU performance states information and configurations
///
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);
}
}
///
/// Gets GPU coolers information
///
public GPUPowerTopologyInformation PowerTopologyInformation { get; }
///
/// Gets GPU system type
///
public SystemType SystemType
{
get => GPUApi.GetSystemType(Handle);
}
///
/// Gets GPU thermal sensors information
///
public GPUThermalInformation ThermalInformation { get; }
///
/// Gets the GPU utilization domains and usages
///
public GPUUsageInformation UsageInformation { get; }
///
public bool Equals(PhysicalGPU other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
///
/// Gets the corresponding instance from a GPU identification number.
///
/// The GPU identification number.
/// An instance of or if operation failed.
public static PhysicalGPU FromGPUId(uint gpuId)
{
var handle = GPUApi.GetPhysicalGPUFromGPUID(gpuId);
if (handle.IsNull)
{
return null;
}
return new PhysicalGPU(handle);
}
///
/// Gets all physical GPUs
///
/// An array of physical GPUs
public static PhysicalGPU[] GetPhysicalGPUs()
{
return GPUApi.EnumPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
///
/// Gets all physical GPUs in TCC state
///
/// An array of physical GPUs
public static PhysicalGPU[] GetTCCPhysicalGPUs()
{
return GPUApi.EnumTCCPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
///
/// Checks for equality between two objects of same type
///
/// The first object
/// The second object
/// true, if both objects are equal, otherwise false
public static bool operator ==(PhysicalGPU left, PhysicalGPU right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
///
/// Checks for inequality between two objects of same type
///
/// The first object
/// The second object
/// true, if both objects are not equal, otherwise false
public static bool operator !=(PhysicalGPU left, PhysicalGPU right)
{
return !(left == right);
}
///
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as PhysicalGPU);
}
///
public override int GetHashCode()
{
return Handle.GetHashCode();
}
///
public override string ToString()
{
return FullName;
}
///
/// Get a list of all active applications for this GPU
///
/// An array of processes
public Process[] GetActiveApplications()
{
return GPUApi.QueryActiveApps(Handle).Select(app => Process.GetProcessById(app.ProcessId)).ToArray();
}
///
/// Get a list of all connected display devices on this GPU
///
/// ConnectedIdsFlag flag
/// An array of display devices
public DisplayDevice[] GetConnectedDisplayDevices(ConnectedIdsFlag flags)
{
return GPUApi.GetConnectedDisplayIds(Handle, flags).Select(display => new DisplayDevice(display)).ToArray();
}
///
/// Get the display device connected to a specific GPU output
///
/// The GPU output to get connected display device for
/// DisplayDevice connected to the specified GPU output
public DisplayDevice GetDisplayDeviceByOutput(GPUOutput output)
{
return new DisplayDevice(GPUApi.GetDisplayIdFromGPUAndOutputId(Handle, output.OutputId));
}
///
/// Get a list of all display devices on any possible output
///
/// An array of display devices
public DisplayDevice[] GetDisplayDevices()
{
return GPUApi.GetAllDisplayIds(Handle).Select(display => new DisplayDevice(display)).ToArray();
}
///
/// Reads EDID data of an output
///
/// The GPU output to read EDID information for
/// A byte array containing EDID data
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;
}
}
///
/// Reads data from the I2C bus
///
/// Information required to read from the I2C bus.
/// The returned payload.
// ReSharper disable once InconsistentNaming
public byte[] ReadI2C(II2CInfo i2cInfo)
{
GPUApi.I2CRead(Handle, ref i2cInfo);
return i2cInfo.Data;
}
///
/// Validates a set of GPU outputs to check if they can be active simultaneously
///
/// GPU outputs to check
/// true if all specified outputs can be active simultaneously, otherwise false
public bool ValidateOutputCombination(GPUOutput[] outputs)
{
var gpuOutpudIds =
outputs.Aggregate(OutputId.Invalid, (current, gpuOutput) => current | gpuOutput.OutputId);
return GPUApi.ValidateOutputCombination(Handle, gpuOutpudIds);
}
///
/// Writes EDID data of an output
///
/// The GPU output to write EDID information for
/// A byte array containing EDID data
public void WriteEDIDData(GPUOutput output, byte[] edidData)
{
WriteEDIDData((uint) output.OutputId, edidData);
}
///
/// Writes EDID data of an display
///
/// The display device to write EDID information for
/// A byte array containing EDID data
public void WriteEDIDData(DisplayDevice display, byte[] edidData)
{
WriteEDIDData(display.DisplayId, edidData);
}
///
/// Writes data to the I2C bus
///
/// Information required to write to the I2C bus including data payload.
// 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();
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();
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));
}
}
}