Пример #1
0
        private uint[] GetClocks()
        {
            NvClocks allClocks = new NvClocks();

            allClocks.Version = NVAPI.GPU_CLOCKS_VER;
            allClocks.Clock   = new uint[NVAPI.MAX_CLOCKS_PER_GPU];
            if (NVAPI.NvAPI_GPU_GetAllClocks != null &&
                NVAPI.NvAPI_GPU_GetAllClocks(_handle, ref allClocks) == NvStatus.OK)
            {
                return(allClocks.Clock);
            }
            return(null);
        }
Пример #2
0
        private static string GetName(NvPhysicalGpuHandle handle)
        {
            string gpuName;

            if (NVAPI.NvAPI_GPU_GetFullName(handle, out gpuName) == NvStatus.OK)
            {
                return(gpuName.Trim());
            }
            else
            {
                return("NVIDIA");
            }
        }
Пример #3
0
        static NvGPUThermalSettings GetThermalSettings(NvPhysicalGpuHandle handle)
        {
            NvGPUThermalSettings settings = new NvGPUThermalSettings();

            settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
            settings.Count   = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
            settings.Sensor  = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
            if (NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
                                                   ref settings) != NvStatus.OK)
            {
                settings.Count = 0;
            }
            return(settings);
        }
        private NvPhysicalGpuHandle?GetNvPhysicalGpuHandle()
        {
            if (_NvPhysicalGpuHandle.HasValue)
            {
                return(_NvPhysicalGpuHandle.Value);
            }
            if (NVAPI.NvAPI_EnumPhysicalGPUs == null)
            {
                Logger.DebugDelayed("NVAPI", "NvAPI_EnumPhysicalGPUs unavailable", TimeSpan.FromMinutes(5));
                return(null);
            }
            if (NVAPI.NvAPI_GPU_GetBusID == null)
            {
                Logger.DebugDelayed("NVAPI", "NvAPI_GPU_GetBusID unavailable", TimeSpan.FromMinutes(5));
                return(null);
            }


            var handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
            var status  = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out _);

            if (status != NvStatus.OK)
            {
                Logger.DebugDelayed("NVAPI", $"Enum physical GPUs failed with status: {status}", TimeSpan.FromMinutes(5));
            }
            else
            {
                foreach (var handle in handles)
                {
                    var idStatus = NVAPI.NvAPI_GPU_GetBusID(handle, out var id);

                    if (idStatus == NvStatus.EXPECTED_PHYSICAL_GPU_HANDLE)
                    {
                        continue;
                    }

                    if (idStatus != NvStatus.OK)
                    {
                        Logger.DebugDelayed("NVAPI", "Bus ID get failed with status: " + idStatus, TimeSpan.FromMinutes(5));
                    }
                    else if (id == BusID)
                    {
                        Logger.DebugDelayed("NVAPI", "Found handle for busid " + id, TimeSpan.FromMinutes(5));
                        _NvPhysicalGpuHandle = handle;
                        return(handle);
                    }
                }
            }
            return(null);
        }
Пример #5
0
        private static Dictionary <int, NvPhysicalGpuHandle> InitNvapi()
        {
            var idHandles = new Dictionary <int, NvPhysicalGpuHandle>();

            if (!NVAPI.IsAvailable)
            {
                return(idHandles);
            }

            var handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];

            if (NVAPI.NvAPI_EnumPhysicalGPUs == null)
            {
                Logger.Debug("NVAPI", "NvAPI_EnumPhysicalGPUs unavailable");
            }
            else
            {
                var status = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out _);
                if (status != NvStatus.OK)
                {
                    Logger.Debug("NVAPI", $"Enum physical GPUs failed with status: {status}");
                }
                else
                {
                    foreach (var handle in handles)
                    {
                        var idStatus = NVAPI.NvAPI_GPU_GetBusID(handle, out var id);

                        if (idStatus == NvStatus.EXPECTED_PHYSICAL_GPU_HANDLE)
                        {
                            continue;
                        }

                        if (idStatus != NvStatus.OK)
                        {
                            Logger.Debug("NVAPI",
                                         "Bus ID get failed with status: " + idStatus);
                        }
                        else
                        {
                            Logger.Debug("NVAPI", "Found handle for busid " + id);
                            idHandles[id] = handle;
                        }
                    }
                }
            }

            return(idHandles);
        }
Пример #6
0
        private NvGPUThermalSettings GetThermalSettings()
        {
            NvGPUThermalSettings settings = new NvGPUThermalSettings();

            settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
            settings.Count   = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
            settings.Sensor  = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
            if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
                  NVAPI.NvAPI_GPU_GetThermalSettings(_handle, (int)NvThermalTarget.ALL,
                                                     ref settings) == NvStatus.OK))
            {
                settings.Count = 0;
            }
            return(settings);
        }
Пример #7
0
        internal DeviceMonitorNVIDIA(NvapiNvmlInfo info)
        {
            UUID        = info.UUID;
            BusID       = info.BusID;
            _nvHandle   = info.nvHandle;
            _nvmlDevice = info.nvmlHandle;

            try
            {
                var powerInfo = new NvGPUPowerInfo
                {
                    Version = NVAPI.GPU_POWER_INFO_VER,
                    Entries = new NvGPUPowerInfoEntry[4]
                };

                var ret = NVAPI.NvAPI_DLL_ClientPowerPoliciesGetInfo(_nvHandle, ref powerInfo);
                if (ret != NvStatus.OK)
                {
                    throw new Exception(ret.ToString());
                }

                Debug.Assert(powerInfo.Entries.Length == 4);

                if (powerInfo.Entries[0].MinPower == 0 || powerInfo.Entries[0].MaxPower == 0)
                {
                    throw new Exception("Power control not available!");
                }

                _minPowerLimit     = powerInfo.Entries[0].MinPower;
                _maxPowerLimit     = powerInfo.Entries[0].MaxPower;
                _defaultPowerLimit = powerInfo.Entries[0].DefPower;

                PowerLimitsEnabled = true;
                // set to high by default
                var defaultLevel = PowerLevel.High;
                var success      = SetPowerTarget(defaultLevel);
                if (!success)
                {
                    Logger.Info("NVML", $"Cannot set power target ({defaultLevel.ToString()}) for device with BusID={BusID}");
                }
            }
            catch (Exception e)
            {
                Logger.Error("NVML", $"Getting power info failed with message \"{e.Message}\", disabling power setting");
                PowerLimitsEnabled = false;
            }
        }
        public NvidiaModelAccessor()
        {
            //This constructor itterates through each of GPU's and generates a NvidiaGpuModel Object for each of them appending.
            int count;
            IDictionary <NvPhysicalGpuHandle, NvDisplayHandle> displayHandles = new Dictionary <NvPhysicalGpuHandle, NvDisplayHandle>();

            NvPhysicalGpuHandle[] handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];

            NvStatus status = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out count);

            for (int i = 0; i < count; i++)
            {
                NvDisplayHandle displayHandle;
                displayHandles.TryGetValue(handles[i], out displayHandle);
                _gpuList.Add(new NvidiaGpuModel(i, handles[i], displayHandle));
            }
        }
Пример #9
0
        public override float NextValue()
        {
            // Update GPU memory load
            NvMemoryInfo memoryInfo = new NvMemoryInfo
            {
                Version = NVAPI.GPU_MEMORY_INFO_VER,
                Values  = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU]
            };

            if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle, ref memoryInfo) == NvStatus.OK)
            {
                uint freeMemory = memoryInfo.Values[4] / 1024;
                return(Math.Max((uint)TotalVram - freeMemory, 0));
            }

            return(0);
        }
Пример #10
0
        private NvPhysicalGpuHandle FindPhysicalGpuHandleForBus(uint bus)
        {
            NvPhysicalGpuHandle[] handlesFromDisplay =
                new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
            if (NVAPI.NvAPI_EnumPhysicalGPUs(handlesFromDisplay, out int count) == NvStatus.OK)
            {
                foreach (NvPhysicalGpuHandle physHandle in handlesFromDisplay)
                {
                    if (NVAPI.NvAPI_GPU_GetBusID(physHandle, out int physBus) == NvStatus.OK && physBus == bus)
                    {
                        return(physHandle);
                    }
                }
            }

            return(new NvPhysicalGpuHandle());
        }
Пример #11
0
        public GpuVramSensor()
        {
            Name = "GPU Memory Load";

            NvMemoryInfo memoryInfo = new NvMemoryInfo
            {
                Version = NVAPI.GPU_MEMORY_INFO_VER,
                Values  = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU]
            };

            if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle, ref memoryInfo) == NvStatus.OK)
            {
                TotalVram = memoryInfo.Values[0] / 1024f;
            }
            else
            {
                TotalVram = 1f;
            }
        }
Пример #12
0
        public bool SetFanSpeedPercentage(int percentage)
        {
            var nvHandle = GetNvPhysicalGpuHandle();

            if (!nvHandle.HasValue)
            {
                Logger.Error("NVAPI", $"SetFanSpeed nvHandle == null");
                return(false);
            }

            var cooler = new nv_fandata {
                count   = 1,
                version = 132040
            };

            var ret = NVAPI.NvAPI_GPU_GetCoolerLevels(nvHandle.Value, 0, ref cooler);

            if (ret != NvStatus.OK)
            {
                Logger.Error("NVAPI", $"GetCoolerLevel failed with status {ret}");
                return(false);
            }

            var levels = new NvGPULevels {
                Version = 65700
            };

            levels.Levels    = new nv_level_internal [20];
            levels.Levels[0] = new nv_level_internal {
                level = percentage, policy = cooler.internals[0].current_policy
            };

            var result = NVAPI.NvAPI_GPU_SetCoolerLevels(nvHandle.Value, 0, ref levels);

            if (result != NvStatus.OK && result != NvStatus.NOT_SUPPORTED)
            {
                // GPUs without fans are not uncommon, so don't treat as error and just return -1
                Logger.Error("NVAPI", $"FanSpeed set failed with status: {result}");
                return(false);
            }
            return(true);
        }
Пример #13
0
        public NVidiaGPU()
        {
            //NvAPI.Initialize();
            //var err = NvAPI.GetErrorMessage(Status.FILE_NOT_FOUND);

            if (available = NVAPI.IsAvailable)
            {
                handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS * 4];

                NvAPI.Initialize();

                var dh = NvAPI.GetAssociatedNvidiaDisplayHandle(@"\\.\DISPLAY1");

                int count;
                var r = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out count);
                if (r != NvStatus.OK)
                {
                    NvDisplayHandle dhnd = new NvDisplayHandle();

                    for (int i = 0; i < NVAPI.MAX_PHYSICAL_GPUS * 2; i++)
                    {
                        var h = NvAPI.EnumNvidiaUnAttachedDisplayHandle(i);

                        if (h != IntPtr.Zero)
                        {
                            Console.WriteLine("Found dev at #{0} ({1:X8})", i, dhnd);
                        }

                        // r = NVAPI.NvAPI_EnumNvidiaDisplayHandle(i, ref dhnd);
                        //if (r != NvStatus.OK)
                        //{
                        //  continue;
                        //}
                        //else
                        //{
                        //  Console.WriteLine("Found dev at #{0} ({1:X8})", i, dhnd);
                        //}
                    }
                }
            }
        }
Пример #14
0
        public void ResetHandles(NvapiNvmlInfo info)
        {
            _nvHandle   = info.nvHandle;
            _nvmlDevice = info.nvmlHandle;

            try
            {
                var powerInfo = new NvGPUPowerInfo
                {
                    Version = NVAPI.GPU_POWER_INFO_VER,
                    Entries = new NvGPUPowerInfoEntry[4]
                };

                var ret = NVAPI.NvAPI_DLL_ClientPowerPoliciesGetInfo(_nvHandle, ref powerInfo);
                if (ret != NvStatus.OK)
                {
                    throw new Exception(ret.ToString());
                }

                Debug.Assert(powerInfo.Entries.Length == 4);

                if (powerInfo.Entries[0].MinPower == 0 || powerInfo.Entries[0].MaxPower == 0)
                {
                    throw new Exception("Power control not available!");
                }

                _minPowerLimit     = powerInfo.Entries[0].MinPower;
                _maxPowerLimit     = powerInfo.Entries[0].MaxPower;
                _defaultPowerLimit = powerInfo.Entries[0].DefPower;
            }
            catch (Exception e)
            {
                Logger.Error("NVML", $"Getting power info failed with message \"{e.Message}\", disabling power setting");
                PowerLimitsEnabled = false;
            }
        }
Пример #15
0
 private void UpdateDriverSettings()
 {
     _driverVersion         = new NvDisplayDriverVersion();
     _driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
     NVAPI.NvAPI_GetDisplayDriverVersion(_displayHandle, ref _driverVersion);
 }
Пример #16
0
        public void Update()
        {
            uint[] values = GetClocks();
            if (values != null)
            {
                _memoryClock = 0.001f * values[8];
                if (values[30] != 0)
                {
                    _coreClock   = 0.0005f * values[30];
                    _shaderClock = 0.001f * values[30];
                }
                else
                {
                    _coreClock   = 0.001f * values[0];
                    _shaderClock = 0.001f * values[14];
                }
            }

            /*
             * Console.Write("core:" + _coreClock.ToString());
             * Console.Write("mem:" + _memoryClock.ToString());
             * Console.Write("shader:" + _shaderClock.ToString());
             * Console.WriteLine();
             */


            NvMemoryInfo memoryInfo = new NvMemoryInfo();

            memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
            memoryInfo.Values  = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
            if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && _displayHandle.HasValue &&
                NVAPI.NvAPI_GPU_GetMemoryInfo(_displayHandle.Value, ref memoryInfo) ==
                NvStatus.OK)
            {
                TotalMem   = memoryInfo.Values[0];
                TotalMemMb = TotalMem / 1024;
                FreeMem    = memoryInfo.Values[4];
                FreeMemMb  = FreeMem / 1024;
                UsedMem    = Math.Max(TotalMem - FreeMem, 0);
                UsedMemMb  = UsedMem / 1024;
                LoadMemPct = 100.0f * UsedMem / TotalMem;
            }


            NvPStates states = new NvPStates();

            states.Version = NVAPI.GPU_PSTATES_VER;
            states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
            if (NVAPI.NvAPI_GPU_GetPStates != null && NVAPI.NvAPI_GPU_GetPStates(_handle, ref states) == NvStatus.OK)
            {
                /*
                 * 0: Core
                 * 1: MemoryController
                 * 2: VideoEngine
                 */
                for (int i = 0; i < 3; i++)
                {
                    if (states.PStates[i].Present)
                    {
                        LoadPct = states.PStates[i].Percentage;
                        break;
                        //Console.WriteLine(states.PStates[i].Percentage);
                    }
                }
            }

            NvGPUThermalSettings thermalSettings = GetThermalSettings();

            for (int i = 0; i < thermalSettings.Count; i++)
            {
                NvSensor sensor = thermalSettings.Sensor[i];
                if (sensor.Target == NvThermalTarget.GPU)
                {
                    Temperature = sensor.CurrentTemp;
                    //Console.WriteLine(temp);
                    break;
                }
            }
        }
Пример #17
0
        public Nvidia()
        {
            bool available = NVAPI.IsAvailable;

            NvPhysicalGpuHandle[] handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
            int count;

            if (NVAPI.NvAPI_EnumPhysicalGPUs == null)
            {
                //Console.WriteLine("Error: NvAPI_EnumPhysicalGPUs not available");
                return;
            }
            else
            {
                NvStatus status = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out count);
                if (status != NvStatus.OK)
                {
                    //Console.WriteLine("Error: NvAPI_EnumPhysicalGPUs not available");
                    //Console.WriteLine("Status: " + status);
                    return;
                }
            }
            IDictionary <NvPhysicalGpuHandle, NvDisplayHandle> displayHandles = new Dictionary <NvPhysicalGpuHandle, NvDisplayHandle>();
            NvDisplayHandle displayHandle;

            if (NVAPI.NvAPI_EnumNvidiaDisplayHandle != null && NVAPI.NvAPI_GetPhysicalGPUsFromDisplay != null)
            {
                NvStatus status = NvStatus.OK;
                int      i      = 0;
                while (status == NvStatus.OK)
                {
                    displayHandle = new NvDisplayHandle();
                    status        = NVAPI.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle);
                    i++;

                    if (status == NvStatus.OK)
                    {
                        NvPhysicalGpuHandle[] handlesFromDisplay = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
                        uint countFromDisplay;
                        if (NVAPI.NvAPI_GetPhysicalGPUsFromDisplay(displayHandle, handlesFromDisplay, out countFromDisplay) == NvStatus.OK)
                        {
                            for (int j = 0; j < countFromDisplay; j++)
                            {
                                if (!displayHandles.ContainsKey(handlesFromDisplay[j]))
                                {
                                    displayHandles.Add(handlesFromDisplay[j], displayHandle);
                                }
                            }
                        }
                    }
                }
            }
            if (count > 1)
            {
                Console.WriteLine("only suppoert 1 GUP");
            }

            displayHandles.TryGetValue(handles[0], out displayHandle);
            this._handle        = handles[0];
            this._displayHandle = displayHandle;
            this.Name           = GetName(this._handle);
        }
Пример #18
0
                public static void QueryCudaDevices()
                {
                    Helpers.ConsolePrint(Tag, "QueryCudaDevices START");
                    QueryCudaDevices(ref _cudaDevices);

                    if (_cudaDevices != null && _cudaDevices.Count != 0)
                    {
                        Available.HasNvidia = true;
                        var stringBuilder = new StringBuilder();
                        stringBuilder.AppendLine("");
                        stringBuilder.AppendLine("CudaDevicesDetection:");

                        // Enumerate NVAPI handles and map to busid
                        var idHandles = new Dictionary <int, NvPhysicalGpuHandle>();
                        if (NVAPI.IsAvailable)
                        {
                            var handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
                            if (NVAPI.NvAPI_EnumPhysicalGPUs == null)
                            {
                                Helpers.ConsolePrint("NVAPI", "NvAPI_EnumPhysicalGPUs unavailable");
                            }
                            else
                            {
                                var status = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out var _);
                                if (status != NvStatus.OK)
                                {
                                    Helpers.ConsolePrint("NVAPI", "Enum physical GPUs failed with status: " + status);
                                }
                                else
                                {
                                    foreach (var handle in handles)
                                    {
                                        var idStatus = NVAPI.NvAPI_GPU_GetBusID(handle, out var id);
                                        if (idStatus != NvStatus.EXPECTED_PHYSICAL_GPU_HANDLE)
                                        {
                                            if (idStatus != NvStatus.OK)
                                            {
                                                Helpers.ConsolePrint("NVAPI",
                                                                     "Bus ID get failed with status: " + idStatus);
                                            }
                                            else
                                            {
                                                Helpers.ConsolePrint("NVAPI", "Found handle for busid " + id);
                                                idHandles[id] = handle;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        var nvmlInit = false;
                        try
                        {
                            var ret = NvmlNativeMethods.nvmlInit();
                            if (ret != nvmlReturn.Success)
                            {
                                throw new Exception($"NVML init failed with code {ret}");
                            }
                            nvmlInit = true;
                        }
                        catch (Exception e)
                        {
                            Helpers.ConsolePrint("NVML", e.ToString());
                        }

                        foreach (var cudaDev in _cudaDevices)
                        {
                            // check sm vesrions
                            bool isUnderSM21;
                            {
                                var isUnderSM2Major = cudaDev.SM_major < 2;
                                var isUnderSM1Minor = cudaDev.SM_minor < 1;
                                isUnderSM21 = isUnderSM2Major && isUnderSM1Minor;
                            }
                            //bool isOverSM6 = cudaDev.SM_major > 6;
                            var          skip               = isUnderSM21;
                            var          skipOrAdd          = skip ? "SKIPED" : "ADDED";
                            const string isDisabledGroupStr = ""; // TODO remove
                            var          etherumCapableStr  = cudaDev.IsEtherumCapable() ? "YES" : "NO";
                            stringBuilder.AppendLine($"\t{skipOrAdd} device{isDisabledGroupStr}:");
                            stringBuilder.AppendLine($"\t\tID: {cudaDev.DeviceID}");
                            stringBuilder.AppendLine($"\t\tBusID: {cudaDev.pciBusID}");
                            stringBuilder.AppendLine($"\t\tNAME: {cudaDev.GetName()}");
                            stringBuilder.AppendLine($"\t\tVENDOR: {cudaDev.VendorName}");
                            stringBuilder.AppendLine($"\t\tUUID: {cudaDev.UUID}");
                            stringBuilder.AppendLine($"\t\tSM: {cudaDev.SMVersionString}");
                            stringBuilder.AppendLine($"\t\tMEMORY: {cudaDev.DeviceGlobalMemory}");
                            stringBuilder.AppendLine($"\t\tETHEREUM: {etherumCapableStr}");

                            if (!skip)
                            {
                                DeviceGroupType group;
                                switch (cudaDev.SM_major)
                                {
                                case 2:
                                    group = DeviceGroupType.NVIDIA_2_1;
                                    break;

                                case 3:
                                    group = DeviceGroupType.NVIDIA_3_x;
                                    break;

                                case 5:
                                    group = DeviceGroupType.NVIDIA_5_x;
                                    break;

                                case 6:
                                    group = DeviceGroupType.NVIDIA_6_x;
                                    break;

                                default:
                                    group = DeviceGroupType.NVIDIA_6_x;
                                    break;
                                }

                                var nvmlHandle = new nvmlDevice();

                                if (nvmlInit)
                                {
                                    var ret = NvmlNativeMethods.nvmlDeviceGetHandleByUUID(cudaDev.UUID, ref nvmlHandle);
                                    stringBuilder.AppendLine(
                                        "\t\tNVML HANDLE: " +
                                        $"{(ret == nvmlReturn.Success ? nvmlHandle.Pointer.ToString() : $"Failed with code ret {ret}")}");
                                }

                                idHandles.TryGetValue(cudaDev.pciBusID, out var handle);
                                Available.Devices.Add(
                                    new CudaComputeDevice(cudaDev, group, ++GpuCount, handle, nvmlHandle)
                                    );
                            }
                        }
                        Helpers.ConsolePrint(Tag, stringBuilder.ToString());
                    }
Пример #19
0
        public GpuSensor()
        {
            if (!NVAPI.IsAvailable)
            {
                throw new Exception("Unable to obtain primary GPU; NVAPI is not available");
            }

            NvPhysicalGpuHandle[] handles = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];

            int numGpus;

            if (NVAPI.NvAPI_EnumPhysicalGPUs == null)
            {
                throw new Exception("Unable to obtain primary GPU; NvAPI_EnumPhysicalGPUs not available");
            }
            else
            {
                NvStatus status = NVAPI.NvAPI_EnumPhysicalGPUs(handles, out numGpus);
                if (status != NvStatus.OK)
                {
                    throw new Exception("Unable to obtain primary GPU");
                }
            }

            if (numGpus < 1)
            {
                throw new Exception("Unable to obtain primary GPU");
            }

            gpuHandle = handles[0];

            IDictionary <NvPhysicalGpuHandle, NvDisplayHandle> displayHandles = new Dictionary <NvPhysicalGpuHandle, NvDisplayHandle>();

            if (NVAPI.NvAPI_EnumNvidiaDisplayHandle != null && NVAPI.NvAPI_GetPhysicalGPUsFromDisplay != null)
            {
                int      i      = 0;
                NvStatus status = NvStatus.OK;
                while (status == NvStatus.OK)
                {
                    NvDisplayHandle displayHandle = new NvDisplayHandle();
                    status = NVAPI.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle);
                    i++;

                    if (status == NvStatus.OK)
                    {
                        NvPhysicalGpuHandle[] handlesFromDisplay = new NvPhysicalGpuHandle[NVAPI.MAX_PHYSICAL_GPUS];
                        if (NVAPI.NvAPI_GetPhysicalGPUsFromDisplay(displayHandle, handlesFromDisplay, out uint countFromDisplay) == NvStatus.OK)
                        {
                            for (int j = 0; j < countFromDisplay; j++)
                            {
                                if (!displayHandles.ContainsKey(handlesFromDisplay[j]))
                                {
                                    displayHandles.Add(handlesFromDisplay[j], displayHandle);
                                }
                            }
                        }
                    }
                }
            }

            displayHandles.TryGetValue(handles[0], out displayHandle);
        }