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)); } } }