using GHelper.Helpers; using NvAPIWrapper.GPU; using NvAPIWrapper.Native; using NvAPIWrapper.Native.GPU; using NvAPIWrapper.Native.GPU.Structures; using NvAPIWrapper.Native.Interfaces.GPU; using System.Diagnostics; using static NvAPIWrapper.Native.GPU.Structures.PerformanceStates20InfoV1; namespace GHelper.Gpu.NVidia; public class NvidiaGpuControl : IGpuControl { public static int MaxCoreOffset => AppConfig.Get("max_gpu_core", 250); public static int MaxMemoryOffset => AppConfig.Get("max_gpu_memory", 500); public static int MinCoreOffset = AppConfig.Get("min_gpu_core", -250); public static int MinMemoryOffset = AppConfig.Get("min_gpu_memory", -500); public const int MinClockLimit = 400; public const int MaxClockLimit = 3000; private static PhysicalGPU? _internalGpu; public NvidiaGpuControl() { _internalGpu = GetInternalDiscreteGpu(); } public bool IsValid => _internalGpu != null; public bool IsNvidia => IsValid; public string FullName => _internalGpu!.FullName; public int? GetCurrentTemperature() { if (!IsValid) return null; PhysicalGPU internalGpu = _internalGpu!; IThermalSensor? gpuSensor = GPUApi.GetThermalSettings(internalGpu.Handle).Sensors .FirstOrDefault(s => s.Target == ThermalSettingsTarget.GPU); return gpuSensor?.CurrentTemperature; } public void Dispose() { } public void KillGPUApps() { if (!IsValid) return; PhysicalGPU internalGpu = _internalGpu!; try { Process[] processes = internalGpu.GetActiveApplications(); foreach (Process process in processes) try { Logger.WriteLine("Kill:" + process.ProcessName); ProcessHelper.KillByProcess(process); } catch (Exception ex) { Logger.WriteLine(ex.Message); } } catch (Exception ex) { Logger.WriteLine(ex.Message); } //GeneralApi.RestartDisplayDriver(); } public bool GetClocks(out int core, out int memory) { PhysicalGPU internalGpu = _internalGpu!; //Logger.WriteLine(internalGpu.FullName); //Logger.WriteLine(internalGpu.ArchitectInformation.ToString()); try { IPerformanceStates20Info states = GPUApi.GetPerformanceStates20(internalGpu.Handle); core = states.Clocks[PerformanceStateId.P0_3DPerformance][0].FrequencyDeltaInkHz.DeltaValue / 1000; memory = states.Clocks[PerformanceStateId.P0_3DPerformance][1].FrequencyDeltaInkHz.DeltaValue / 1000; Logger.WriteLine($"GET GPU CLOCKS: {core}, {memory}"); foreach (var delta in states.Voltages[PerformanceStateId.P0_3DPerformance]) { Logger.WriteLine("GPU VOLT:" + delta.IsEditable + " - " + delta.ValueDeltaInMicroVolt.DeltaValue); } return true; } catch (Exception ex) { Logger.WriteLine("GET GPU CLOCKS:" + ex.Message); core = memory = 0; return false; } } private bool RunPowershellCommand(string script) { try { ProcessHelper.RunCMD("powershell", script); return true; } catch (Exception ex) { Logger.WriteLine(ex.ToString()); return false; } } public int GetMaxGPUCLock() { PhysicalGPU internalGpu = _internalGpu!; try { PrivateClockBoostLockV2 data = GPUApi.GetClockBoostLock(internalGpu.Handle); int limit = (int)data.ClockBoostLocks[0].VoltageInMicroV / 1000; Logger.WriteLine("GET CLOCK LIMIT: " + limit); return limit; } catch (Exception ex) { Logger.WriteLine("GET CLOCK LIMIT: " + ex.Message); return -1; } } public int SetMaxGPUClock(int clock) { if (clock < MinClockLimit || clock >= MaxClockLimit) clock = 0; int _clockLimit = GetMaxGPUCLock(); if (_clockLimit < 0 && clock == 0) return 0; if (_clockLimit != clock) { if (clock > 0) RunPowershellCommand($"nvidia-smi -lgc 0,{clock}"); else RunPowershellCommand($"nvidia-smi -rgc"); return 1; } else { return 0; } } public bool RestartGPU() { return RunPowershellCommand(@"$device = Get-PnpDevice | Where-Object { $_.FriendlyName -imatch 'NVIDIA' -and $_.Class -eq 'Display' }; Disable-PnpDevice $device.InstanceId -Confirm:$false; Start-Sleep -Seconds 5; Enable-PnpDevice $device.InstanceId -Confirm:$false"); } public int SetClocks(int core, int memory) { if (core < MinCoreOffset || core > MaxCoreOffset) return 0; if (memory < MinMemoryOffset || memory > MaxMemoryOffset) return 0; GetClocks(out int currentCore, out int currentMemory); // Nothing to set if (Math.Abs(core - currentCore) < 5 && Math.Abs(memory - currentMemory) < 5) return 0; PhysicalGPU internalGpu = _internalGpu!; var coreClock = new PerformanceStates20ClockEntryV1(PublicClockDomain.Graphics, new PerformanceStates20ParameterDelta(core * 1000)); var memoryClock = new PerformanceStates20ClockEntryV1(PublicClockDomain.Memory, new PerformanceStates20ParameterDelta(memory * 1000)); //var voltageEntry = new PerformanceStates20BaseVoltageEntryV1(PerformanceVoltageDomain.Core, new PerformanceStates20ParameterDelta(voltage)); PerformanceStates20ClockEntryV1[] clocks = { coreClock, memoryClock }; PerformanceStates20BaseVoltageEntryV1[] voltages = { }; PerformanceState20[] performanceStates = { new PerformanceState20(PerformanceStateId.P0_3DPerformance, clocks, voltages) }; var overclock = new PerformanceStates20InfoV1(performanceStates, 2, 0); try { Logger.WriteLine($"SET GPU CLOCKS: {core}, {memory}"); GPUApi.SetPerformanceStates20(internalGpu.Handle, overclock); } catch (Exception ex) { Logger.WriteLine("SET GPU CLOCKS: " + ex.Message); return -1; } return 1; } private static PhysicalGPU? GetInternalDiscreteGpu() { try { return PhysicalGPU .GetPhysicalGPUs() .FirstOrDefault(gpu => gpu.SystemType == SystemType.Laptop); } catch (Exception ex) { Debug.WriteLine(ex.Message); return null; } } public int? GetGpuUse() { if (!IsValid) return null; PhysicalGPU internalGpu = _internalGpu!; IUtilizationDomainInfo? gpuUsage = GPUApi.GetUsages(internalGpu.Handle).GPU; return (int?)gpuUsage?.Percentage; } }