using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using Microsoft.Win32.SafeHandles; using DisplayMagicianShared; using System.ComponentModel; using DisplayMagicianShared.Windows; using EDIDParser; namespace DisplayMagicianShared.NVIDIA { [StructLayout(LayoutKind.Sequential)] public struct NVIDIA_MOSAIC_CONFIG : IEquatable { public bool IsMosaicEnabled; public NV_MOSAIC_TOPO_BRIEF MosaicTopologyBrief; public NV_MOSAIC_DISPLAY_SETTING_V2 MosaicDisplaySettings; public Int32 OverlapX; public Int32 OverlapY; public NV_MOSAIC_GRID_TOPO_V2[] MosaicGridTopos; public UInt32 MosaicGridCount; public List MosaicViewports; public UInt32 PrimaryDisplayId; public bool Equals(NVIDIA_MOSAIC_CONFIG other) => IsMosaicEnabled == other.IsMosaicEnabled && MosaicTopologyBrief.Equals(other.MosaicTopologyBrief) && MosaicDisplaySettings.Equals(other.MosaicDisplaySettings) && OverlapX == other.OverlapX && OverlapY == other.OverlapY && MosaicGridTopos.Equals(other.MosaicGridTopos) && MosaicGridCount == other.MosaicGridCount && MosaicViewports.Equals(other.MosaicViewports) && PrimaryDisplayId == other.PrimaryDisplayId; public override int GetHashCode() { return (IsMosaicEnabled, MosaicTopologyBrief, MosaicDisplaySettings, OverlapX, OverlapY, MosaicGridTopos, MosaicGridCount, MosaicViewports, PrimaryDisplayId).GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] public struct NVIDIA_HDR_CONFIG : IEquatable { public Dictionary HdrCapabilities; public Dictionary HdrColorData; public bool IsNvHdrEnabled; public bool Equals(NVIDIA_HDR_CONFIG other) => HdrCapabilities == other.HdrCapabilities && HdrColorData == other.HdrColorData && IsNvHdrEnabled == other.IsNvHdrEnabled; public override int GetHashCode() { return (HdrCapabilities, HdrColorData, IsNvHdrEnabled).GetHashCode(); } } [StructLayout(LayoutKind.Sequential)] public struct NVIDIA_DISPLAY_CONFIG : IEquatable { public NVIDIA_MOSAIC_CONFIG MosaicConfig; public NVIDIA_HDR_CONFIG HdrConfig; public List DisplayIdentifiers; public bool Equals(NVIDIA_DISPLAY_CONFIG other) => MosaicConfig.Equals(other.MosaicConfig) && HdrConfig.Equals(other.HdrConfig); public override int GetHashCode() { return (MosaicConfig, HdrConfig).GetHashCode(); } } public class NVIDIALibrary : IDisposable { // Static members are 'eagerly initialized', that is, // immediately when class is loaded for the first time. // .NET guarantees thread safety for static initialization private static NVIDIALibrary _instance = new NVIDIALibrary(); private static WinLibrary _winLibrary = new WinLibrary(); private bool _initialised = false; private bool _haveSessionHandle = false; // To detect redundant calls private bool _disposed = false; // Instantiate a SafeHandle instance. private SafeHandle _safeHandle = new SafeFileHandle(IntPtr.Zero, true); private IntPtr _nvapiSessionHandle = IntPtr.Zero; static NVIDIALibrary() { } public NVIDIALibrary() { try { SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: Attempting to load the NVIDIA NVAPI DLL"); // Attempt to prelink all of the NVAPI functions //Marshal.PrelinkAll(typeof(NVImport)); // If we get here then we definitely have the NVIDIA driver available. NVAPI_STATUS NVStatus = NVAPI_STATUS.NVAPI_ERROR; SharedLogger.logger.Trace("NVIDIALibrary/NVIDIALibrary: Intialising NVIDIA NVAPI library interface"); // Step 1: Initialise the NVAPI try { if (NVImport.IsAvailable()) { _initialised = true; SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: NVIDIA NVAPI library was initialised successfully"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: Error intialising NVIDIA NVAPI library. NvAPI_Initialize() returned error code {NVStatus}"); } } catch (Exception ex) { SharedLogger.logger.Trace(ex, $"NVIDIALibrary/NVIDIALibrary: Exception intialising NVIDIA NVAPI library. NvAPI_Initialize() caused an exception."); } // Step 2: Get a session handle that we can use for all other interactions /*try { NVStatus = NVImport.NvAPI_DRS_CreateSession(out _nvapiSessionHandle); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { _haveSessionHandle = true; SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: NVIDIA NVAPI library DRS session handle was created successfully"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: Error creating a NVAPI library DRS session handle. NvAPI_DRS_CreateSession() returned error code {NVStatus}"); } } catch (Exception ex) { SharedLogger.logger.Trace(ex, $"NVIDIALibrary/NVIDIALibrary: Exception creating a NVAPI library DRS session handle. NvAPI_DRS_CreateSession() caused an exception."); }*/ _winLibrary = WinLibrary.GetLibrary(); } catch (DllNotFoundException ex) { // If this fires, then the DLL isn't available, so we need don't try to do anything else SharedLogger.logger.Info(ex, $"NVIDIALibrary/NVIDIALibrary: Exception trying to load the NVIDIA NVAPI DLL. This generally means you don't have the NVIDIA driver installed."); } } ~NVIDIALibrary() { SharedLogger.logger.Trace("NVIDIALibrary/~NVIDIALibrary: Destroying NVIDIA NVAPI library interface"); // If the NVAPI library was initialised, then we need to free it up. if (_initialised) { NVAPI_STATUS NVStatus = NVAPI_STATUS.NVAPI_ERROR; // If we have a session handle we need to free it up first if (_haveSessionHandle) { try { //NVStatus = NVImport.NvAPI_DRS_DestorySession(_nvapiSessionHandle); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { _haveSessionHandle = true; SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: NVIDIA NVAPI library DRS session handle was successfully destroyed"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: Error destroying the NVAPI library DRS session handle. NvAPI_DRS_DestorySession() returned error code {NVStatus}"); } } catch (Exception ex) { SharedLogger.logger.Trace(ex, $"NVIDIALibrary/NVIDIALibrary: Exception destroying the NVIDIA NVAPI library. NvAPI_DRS_DestorySession() caused an exception."); } } try { //NVImport.NvAPI_Unload(); SharedLogger.logger.Trace($"NVIDIALibrary/NVIDIALibrary: NVIDIA NVAPI library was unloaded successfully"); } catch (Exception ex) { SharedLogger.logger.Trace(ex, $"NVIDIALibrary/NVIDIALibrary: Exception unloading the NVIDIA NVAPI library. NvAPI_Unload() caused an exception."); } } } // Public implementation of Dispose pattern callable by consumers. public void Dispose() => Dispose(true); // Protected implementation of Dispose pattern. protected virtual void Dispose(bool disposing) { if (_disposed) { return; } if (disposing) { //NVImport.ADL_Main_Control_Destroy(); // Dispose managed state (managed objects). _safeHandle?.Dispose(); } _disposed = true; } public bool IsInstalled { get { return _initialised; } } public List PCIVendorIDs { get { return new List() { "10DE" }; } } public static NVIDIALibrary GetLibrary() { return _instance; } public NVIDIA_DISPLAY_CONFIG GetActiveConfig() { SharedLogger.logger.Trace($"NVIDIALibrary/GetActiveConfig: Getting the currently active config"); bool allDisplays = false; return GetNVIDIADisplayConfig(allDisplays); } private NVIDIA_DISPLAY_CONFIG GetNVIDIADisplayConfig(bool allDisplays = false) { NVIDIA_DISPLAY_CONFIG myDisplayConfig = new NVIDIA_DISPLAY_CONFIG(); if (_initialised) { // Enumerate all the Physical GPUs PhysicalGpuHandle[] physicalGpus = new PhysicalGpuHandle[NVImport.NV_MAX_PHYSICAL_GPUS]; uint physicalGpuCount = 0; NVAPI_STATUS NVStatus = NVImport.NvAPI_EnumPhysicalGPUs(ref physicalGpus, out physicalGpuCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_EnumPhysicalGPUs returned {physicalGpuCount} Physical GPUs"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting physical GPU count. NvAPI_EnumPhysicalGPUs() returned error code {NVStatus}"); } // Go through the Physical GPUs one by one for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++) { //This function retrieves the Quadro status for the GPU (1 if Quadro, 0 if GeForce) uint quadroStatus = 0; NVStatus = NVImport.NvAPI_GPU_GetQuadroStatus(physicalGpus[physicalGpuIndex], out quadroStatus); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { if (quadroStatus == 0) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is one from the GeForce range"); } else if (quadroStatus == 1) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is one from the Quadro range"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is neither a GeForce or Quadro range vodeo card (QuadroStatus = {quadroStatus})"); } } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error GETTING qUADRO STATUS. NvAPI_GPU_GetQuadroStatus() returned error code {NVStatus}"); } } // Get current Mosaic Topology settings in brief (check whether Mosaic is on) NV_MOSAIC_TOPO_BRIEF mosaicTopoBrief = new NV_MOSAIC_TOPO_BRIEF(); NV_MOSAIC_DISPLAY_SETTING_V2 mosaicDisplaySettings = new NV_MOSAIC_DISPLAY_SETTING_V2(); int mosaicOverlapX = 0; int mosaicOverlapY = 0; NVStatus = NVImport.NvAPI_Mosaic_GetCurrentTopo(ref mosaicTopoBrief, ref mosaicDisplaySettings, out mosaicOverlapX, out mosaicOverlapY); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } // Check if there is a topology and that Mosaic is enabled if (mosaicTopoBrief.Topo != NV_MOSAIC_TOPO.NV_MOSAIC_TOPO_NONE && mosaicTopoBrief.Enabled == 1) { // Mosaic is enabled! SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Mosaic is enabled."); myDisplayConfig.MosaicConfig.MosaicTopologyBrief = mosaicTopoBrief; myDisplayConfig.MosaicConfig.MosaicDisplaySettings = mosaicDisplaySettings; myDisplayConfig.MosaicConfig.OverlapX = mosaicOverlapX; myDisplayConfig.MosaicConfig.OverlapY = mosaicOverlapY; myDisplayConfig.MosaicConfig.IsMosaicEnabled = true; // Get more Mosaic Topology detailed settings NV_MOSAIC_TOPO_GROUP mosaicTopoGroup = new NV_MOSAIC_TOPO_GROUP(); NVStatus = NVImport.NvAPI_Mosaic_GetTopoGroup(ref mosaicTopoBrief, ref mosaicTopoGroup); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The version of the structure passed in is not supported by this driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } // Figure out how many Mosaic Grid topoligies there are uint mosaicGridCount = 0; NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } // Get Current Mosaic Grid settings using the Grid topologies fnumbers we got before NV_MOSAIC_GRID_TOPO_V2[] mosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[mosaicGridCount]; NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridTopos, ref mosaicGridCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } myDisplayConfig.MosaicConfig.MosaicGridTopos = mosaicGridTopos; myDisplayConfig.MosaicConfig.MosaicGridCount = mosaicGridCount; List allViewports = new List { }; foreach (NV_MOSAIC_GRID_TOPO_V2 gridTopo in mosaicGridTopos) { // Get Current Mosaic Grid settings using the Grid topologies numbers we got before NV_RECT[] viewports = new NV_RECT[NVImport.NV_MOSAIC_MAX_DISPLAYS]; byte bezelCorrected = 0; NVStatus = NVImport.NvAPI_Mosaic_GetDisplayViewportsByResolution(gridTopo.Displays[0].DisplayId, 0, 0, ref viewports, ref bezelCorrected); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_MOSAIC_NOT_ACTIVE) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The requested action cannot be performed without Mosaic being enabled. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } // Save the viewports to the List allViewports.Add(viewports); } myDisplayConfig.MosaicConfig.MosaicViewports = allViewports; } else { // Mosaic isn't enabled SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Mosaic is NOT enabled."); myDisplayConfig.MosaicConfig.MosaicTopologyBrief = mosaicTopoBrief; myDisplayConfig.MosaicConfig.IsMosaicEnabled = false; myDisplayConfig.MosaicConfig.MosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[] { }; myDisplayConfig.MosaicConfig.MosaicViewports = new List(); } // Check if Mosaic is possible and log that so we know if troubleshooting bugs if (mosaicTopoBrief.IsPossible == 1) { // Mosaic is possible! SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Mosaic is possible. Mosaic topology would be {mosaicTopoBrief.Topo.ToString("G")}."); } else { // Mosaic isn't possible SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Mosaic is NOT possible."); } // We want to get the primary monitor NVStatus = NVImport.NvAPI_DISP_GetGDIPrimaryDisplayId(out UInt32 primaryDisplayId); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetGDIPrimaryDisplayId returned OK."); myDisplayConfig.MosaicConfig.PrimaryDisplayId = primaryDisplayId; } else if (NVStatus == NVAPI_STATUS.NVAPI_NVIDIA_DEVICE_NOT_FOUND) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: There are no NVIDIA video cards in this computer. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } // We want to get the number of displays we have // Go through the Physical GPUs one by one for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++) { //This function retrieves the number of display IDs we know about UInt32 displayCount = 0; NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayCount, 0); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetGDIPrimaryDisplayId returned OK. We have {displayCount} physical GPUs"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } if (displayCount > 0) { // Now we try to get the information about the displayIDs NV_GPU_DISPLAYIDS_V2[] displayIds = new NV_GPU_DISPLAYIDS_V2[displayCount]; NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayIds, ref displayCount, 0); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetConnectedDisplayIds returned OK. We have {displayCount} physical GPUs"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } // Time to get the HDR capabilities and settings for each display bool isNvHdrEnabled = false; Dictionary allHdrCapabilities = new Dictionary(); Dictionary allHdrColorData = new Dictionary(); for (int displayIndex = 0; displayIndex < displayCount; displayIndex++) { if (allDisplays) { // We want all physicallyconnected or connected displays if (!(displayIds[displayIndex].isConnected || displayIds[displayIndex].isPhysicallyConnected)) { continue; } } else { // We want only active displays, so skip any non-active ones if (!displayIds[displayIndex].IsActive) { continue; } } // Now we get the HDR capabilities of the display NV_HDR_CAPABILITIES_V2 hdrCapabilities = new NV_HDR_CAPABILITIES_V2(); NVStatus = NVImport.NvAPI_Disp_GetHdrCapabilities(displayIds[displayIndex].DisplayId, ref hdrCapabilities); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Disp_GetHdrCapabilities returned OK."); if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.IsST2084EotfSupported)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports HDR mode ST2084 EOTF"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support HDR mode ST2084 EOTF"); } if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.IsDolbyVisionSupported)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports DolbyVision HDR"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support DolbyVision HDR"); } if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.IsEdrSupported)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports EDR"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support EDR"); } if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.IsTraditionalHdrGammaSupported)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports Traditional HDR Gama"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support Traditional HDR Gama"); } if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.IsTraditionalSdrGammaSupported)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports Traditional SDR Gama"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT supports Traditional SDR Gama"); } if (hdrCapabilities.SupportFlags.HasFlag(NV_HDR_CAPABILITIES_V2_FLAGS.DriverExpandDefaultHdrParameters)) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} supports Driver Expanded Default HDR Parameters"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Display {displayIds[displayIndex].DisplayId} DOES NOT support Driver Expanded Default HDR Parameters "); } allHdrCapabilities.Add(displayIds[displayIndex].DisplayId, hdrCapabilities); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting HDR color capabilities from your display! NvAPI_Disp_GetHdrCapabilities() returned error code {NVStatus}. It's most likely that your monitor {displayIds[displayIndex].DisplayId} doesn't support HDR."); } // Now we get the HDR colour settings of the display NV_HDR_COLOR_DATA_V2 hdrColorData = new NV_HDR_COLOR_DATA_V2(); NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayIds[displayIndex].DisplayId, ref hdrColorData); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Disp_HdrColorControl returned OK. HDR mode is currently {hdrColorData.HdrMode.ToString("G")}."); if (hdrColorData.HdrMode != NV_HDR_MODE.NV_HDR_MODE_OFF) { isNvHdrEnabled = true; } allHdrColorData.Add(displayIds[displayIndex].DisplayId, hdrColorData); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}."); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting HDR color settings! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayIds[displayIndex].DisplayId} doesn't support HDR."); } } // Store the HDR information myDisplayConfig.HdrConfig.IsNvHdrEnabled = isNvHdrEnabled; myDisplayConfig.HdrConfig.HdrCapabilities = allHdrCapabilities; myDisplayConfig.HdrConfig.HdrColorData = allHdrColorData; } } myDisplayConfig.DisplayIdentifiers = GetCurrentDisplayIdentifiers(); } else { SharedLogger.logger.Error($"NVIDIALibrary/GetNVIDIADisplayConfig: ERROR - Tried to run GetNVIDIADisplayConfig but the NVIDIA ADL library isn't initialised!"); throw new NVIDIALibraryException($"Tried to run GetNVIDIADisplayConfig but the NVIDIA ADL library isn't initialised!"); } // Return the configuration return myDisplayConfig; } public string PrintActiveConfig() { string stringToReturn = ""; // Get the current config NVIDIA_DISPLAY_CONFIG displayConfig = GetActiveConfig(); stringToReturn += $"****** NVIDIA VIDEO CARDS *******\n"; // Enumerate all the Physical GPUs PhysicalGpuHandle[] physicalGpus = new PhysicalGpuHandle[NVImport.NV_MAX_PHYSICAL_GPUS]; uint physicalGpuCount = 0; NVAPI_STATUS NVStatus = NVImport.NvAPI_EnumPhysicalGPUs(ref physicalGpus, out physicalGpuCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_EnumPhysicalGPUs returned {physicalGpuCount} Physical GPUs"); stringToReturn += $"Number of NVIDIA Video cards found: {physicalGpuCount}\n"; } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting physical GPU count. NvAPI_EnumPhysicalGPUs() returned error code {NVStatus}"); } // Go through the Physical GPUs one by one for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++) { //We want to get the name of the physical device string gpuName = ""; NVStatus = NVImport.NvAPI_GPU_GetFullName(physicalGpus[physicalGpuIndex], ref gpuName); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetFullName returned OK. The GPU Full Name is {gpuName}"); stringToReturn += $"NVIDIA Video card #{physicalGpuIndex} is a {gpuName}\n"; } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting the GPU full name! NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } //This function retrieves the Quadro status for the GPU (1 if Quadro, 0 if GeForce) uint quadroStatus = 0; NVStatus = NVImport.NvAPI_GPU_GetQuadroStatus(physicalGpus[physicalGpuIndex], out quadroStatus); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { if (quadroStatus == 0) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is one from the GeForce range"); stringToReturn += $"NVIDIA Video card #{physicalGpuIndex} is in the GeForce range\n"; } else if (quadroStatus == 1) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is one from the Quadro range"); stringToReturn += $"NVIDIA Video card #{physicalGpuIndex} is in the Quadro range\n"; } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NVIDIA Video Card is neither a GeForce or Quadro range vodeo card (QuadroStatus = {quadroStatus})"); } } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error GETTING qUADRO STATUS. NvAPI_GPU_GetQuadroStatus() returned error code {NVStatus}"); } } stringToReturn += $"\n****** NVIDIA SURROUND/MOSAIC *******\n"; if (displayConfig.MosaicConfig.IsMosaicEnabled) { stringToReturn += $"NVIDIA Surround/Mosaic is Enabled\n"; if (displayConfig.MosaicConfig.MosaicGridTopos.Length > 1) { stringToReturn += $"There are {displayConfig.MosaicConfig.MosaicGridTopos.Length} NVIDIA Surround/Mosaic Grid Topologies in use.\n"; } if (displayConfig.MosaicConfig.MosaicGridTopos.Length == 1) { stringToReturn += $"There is 1 NVIDIA Surround/Mosaic Grid Topology in use.\n"; } else { stringToReturn += $"There are no NVIDIA Surround/Mosaic Grid Topologies in use.\n"; } int count = 0; foreach (NV_MOSAIC_GRID_TOPO_V2 gridTopology in displayConfig.MosaicConfig.MosaicGridTopos) { stringToReturn += $"NOTE: This Surround/Mosaic screen will be treated as a single display by Windows.\n"; stringToReturn += $"The NVIDIA Surround/Mosaic Grid Topology #{count} is {gridTopology.Rows} Rows x {gridTopology.Columns} Columns\n"; stringToReturn += $"The NVIDIA Surround/Mosaic Grid Topology #{count} involves {gridTopology.DisplayCount} Displays\n"; count++; } } else { stringToReturn += $"NVIDIA Surround/Mosaic is Disabled\n"; } // Start printing out things stringToReturn += $"\n****** NVIDIA HDR CONFIG *******\n"; if (displayConfig.HdrConfig.IsNvHdrEnabled) { stringToReturn += $"NVIDIA HDR is Enabled\n"; if (displayConfig.HdrConfig.HdrCapabilities.Count > 0) { stringToReturn += $"There are {displayConfig.HdrConfig.HdrCapabilities.Count} NVIDIA HDR devices in use.\n"; } if (displayConfig.MosaicConfig.MosaicGridTopos.Length == 1) { stringToReturn += $"There is 1 NVIDIA HDR devices in use.\n"; } else { stringToReturn += $"There are no NVIDIA HDR devices in use.\n"; } foreach (KeyValuePair hdrCapabilityItem in displayConfig.HdrConfig.HdrCapabilities) { string displayId = hdrCapabilityItem.Key.ToString(); if (hdrCapabilityItem.Value.IsDolbyVisionSupported) { stringToReturn += $"Display {displayId} supports DolbyVision HDR.\n"; } else { stringToReturn += $"Display {displayId} DOES NOT support DolbyVision HDR.\n"; } if (hdrCapabilityItem.Value.IsST2084EotfSupported) { stringToReturn += $"Display {displayId} supports ST2084EOTF HDR Mode.\n"; } else { stringToReturn += $"Display {displayId} DOES NOT support ST2084EOTF HDR Mode.\n"; } if (hdrCapabilityItem.Value.IsTraditionalHdrGammaSupported) { stringToReturn += $"Display {displayId} supports Traditional HDR Gamma.\n"; } else { stringToReturn += $"Display {displayId} DOES NOT support Traditional HDR Gamma.\n"; } if (hdrCapabilityItem.Value.IsEdrSupported) { stringToReturn += $"Display {displayId} supports EDR.\n"; } else { stringToReturn += $"Display {displayId} DOES NOT support EDR.\n"; } if (hdrCapabilityItem.Value.IsTraditionalSdrGammaSupported) { stringToReturn += $"Display {displayId} supports SDR Gamma.\n"; } else { stringToReturn += $"Display {displayId} DOES NOT support SDR Gamma.\n"; } } } else { stringToReturn += $"NVIDIA HDR is Disabled (HDR may still be enabled within Windows itself)\n"; } stringToReturn += $"\n\n"; // Now we also get the Windows CCD Library info, and add it to the above stringToReturn += WinLibrary.GetLibrary().PrintActiveConfig(); return stringToReturn; } public bool SetActiveConfig(NVIDIA_DISPLAY_CONFIG displayConfig) { if (_initialised) { NVAPI_STATUS NVStatus = NVAPI_STATUS.NVAPI_ERROR; // We want to get the current config NVIDIA_DISPLAY_CONFIG currentDisplayConfig = GetNVIDIADisplayConfig(); // We want to check the NVIDIA Surround (Mosaic) config is valid SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Testing whether the display configuration is valid"); // if (displayConfig.MosaicConfig.IsMosaicEnabled) { // We need to change to a Mosaic profile, so we need to apply the new Mosaic Topology NV_MOSAIC_SETDISPLAYTOPO_FLAGS setTopoFlags = NV_MOSAIC_SETDISPLAYTOPO_FLAGS.NONE; SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Yay! The display settings provided are valid to apply! Attempting to apply them now."); // If we get here then the display is valid, so now we actually apply the new Mosaic Topology NVStatus = NVImport.NvAPI_Mosaic_SetDisplayGrids(displayConfig.MosaicConfig.MosaicGridTopos, displayConfig.MosaicConfig.MosaicGridCount, setTopoFlags); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_ACTIVE_SLI_TOPOLOGY) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: No matching GPU topologies could be found. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); return false; } else if (NVStatus == NVAPI_STATUS.NVAPI_TOPO_NOT_POSSIBLE) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: The topology passed in is not currently possible. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); return false; } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_MODE_CHANGE_FAILED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: There was an error changing the display mode. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); return false; } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Mosaic_SetDisplayGrids() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } } else if (!displayConfig.MosaicConfig.IsMosaicEnabled && currentDisplayConfig.MosaicConfig.IsMosaicEnabled) { // We are on a Mosaic profile now, and we need to change to a non-Mosaic profile // We need to disable the Mosaic Topology // Turn off Mosaic uint enable = 0; NVStatus = NVImport.NvAPI_Mosaic_EnableCurrentTopo(enable); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_TOPO_NOT_POSSIBLE) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The topology passed in is not currently possible. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); return false; } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_MODE_CHANGE_FAILED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: There was an error disabling the display mode. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); return false; } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } } else if (!displayConfig.MosaicConfig.IsMosaicEnabled && !currentDisplayConfig.MosaicConfig.IsMosaicEnabled) { // We are on a non-Mosaic profile now, and we are changing to a non-Mosaic profile // so there is nothing to do as far as NVIDIA is concerned! SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We are on a non-Mosaic profile now, and we are changing to a non-Mosaic profile so there is nothing to do as far as NVIDIA is concerned!"); } // Now, we have the current HDR settings, and the existing HDR settings, so we go through and we attempt to set each display color settings foreach (var wantedHdrColorData in displayConfig.HdrConfig.HdrColorData) { // If we have HDR settings for the display, then attempt to set them if (currentDisplayConfig.HdrConfig.HdrColorData.ContainsKey(wantedHdrColorData.Key)) { // Now we set the HDR colour settings of the display NV_HDR_COLOR_DATA_V2 hdrColorData = wantedHdrColorData.Value; NVStatus = NVImport.NvAPI_Disp_HdrColorControl(wantedHdrColorData.Key, ref hdrColorData); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_HdrColorControl returned OK. We just successfully set the HDR mode to {hdrColorData.HdrMode.ToString("G")}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {wantedHdrColorData.Key} doesn't support HDR."); } } } } else { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: ERROR - Tried to run SetActiveConfig but the NVIDIA NVAPI library isn't initialised!"); throw new NVIDIALibraryException($"Tried to run SetActiveConfig but the NVIDIA NVAPI library isn't initialised!"); } return true; } public bool IsActiveConfig(NVIDIA_DISPLAY_CONFIG displayConfig) { // Get the current windows display configs to compare to the one we loaded bool allDisplays = false; NVIDIA_DISPLAY_CONFIG currentDisplayConfig = GetNVIDIADisplayConfig(allDisplays); // Check whether the display config is in use now SharedLogger.logger.Trace($"NVIDIALibrary/IsActiveConfig: Checking whether the display configuration is already being used."); if (displayConfig.Equals(currentDisplayConfig)) { SharedLogger.logger.Trace($"NVIDIALibrary/IsActiveConfig: The display configuration is already being used (supplied displayConfig Equals currentDisplayConfig"); return true; } else { SharedLogger.logger.Trace($"NVIDIALibrary/IsActiveConfig: The display configuration is NOT currently in use (supplied displayConfig does NOT equal currentDisplayConfig"); return false; } } public bool IsValidConfig(NVIDIA_DISPLAY_CONFIG displayConfig) { // We want to check the NVIDIA Surround (Mosaic) config is valid SharedLogger.logger.Trace($"NVIDIALibrary/IsValidConfig: Testing whether the display configuration is valid"); // if (displayConfig.MosaicConfig.IsMosaicEnabled) { // =================================================================================================================================== // Important! ValidateDisplayGrids does not work at the moment. It errors when supplied with a Grid Topology that works in SetDisplaGrids // We therefore cannot use ValidateDisplayGrids to actually validate the config before it's use. We instead need to rely on SetDisplaGrids reporting an // error if it is unable to apply the requested configuration. While this works fine, it's not optimal. // TODO: Test ValidateDisplayGrids in a future NVIDIA driver release to see if they fixed it. // =================================================================================================================================== return true; /*// Figure out how many Mosaic Grid topoligies there are uint mosaicGridCount = 0; NVAPI_STATUS NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } // Get Current Mosaic Grid settings using the Grid topologies fnumbers we got before //NV_MOSAIC_GRID_TOPO_V2[] mosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V2[mosaicGridCount]; NV_MOSAIC_GRID_TOPO_V1[] mosaicGridTopos = new NV_MOSAIC_GRID_TOPO_V1[mosaicGridCount]; NVStatus = NVImport.NvAPI_Mosaic_EnumDisplayGrids(ref mosaicGridTopos, ref mosaicGridCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_GetCurrentTopo() returned error code {NVStatus}"); } */ /*NV_MOSAIC_SETDISPLAYTOPO_FLAGS setTopoFlags = NV_MOSAIC_SETDISPLAYTOPO_FLAGS.NONE; bool topoValid = false; NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[] topoStatuses = new NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[displayConfig.MosaicConfig.MosaicGridCount]; NVAPI_STATUS NVStatus = NVImport.NvAPI_Mosaic_ValidateDisplayGrids(setTopoFlags, ref displayConfig.MosaicConfig.MosaicGridTopos, ref topoStatuses, displayConfig.MosaicConfig.MosaicGridCount); //NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[] topoStatuses = new NV_MOSAIC_DISPLAY_TOPO_STATUS_V1[mosaicGridCount]; //NVStatus = NVImport.NvAPI_Mosaic_ValidateDisplayGrids(setTopoFlags, ref mosaicGridTopos, ref topoStatuses, mosaicGridCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_GetCurrentTopo returned OK."); for (int i = 0; i < topoStatuses.Length; i++) { // If there is an error then we need to log it! // And make it not be used if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.OK) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Congratulations! No error flags for GridTopology #{i}"); topoValid = true; } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.DISPLAY_ON_INVALID_GPU) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Display is on an invalid GPU"); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.DISPLAY_ON_WRONG_CONNECTOR) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Display is on the wrong connection. It was on a different connection when the display profile was saved."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.ECC_ENABLED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: ECC has been enabled, and Mosaic/Surround doesn't work with ECC"); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.GPU_TOPOLOGY_NOT_SUPPORTED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: This GPU topology is not supported."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.MISMATCHED_OUTPUT_TYPE) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: The output type has changed for the display. The display was connected through another output type when the display profile was saved."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NOT_SUPPORTED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: This Grid Topology is not supported on this video card."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_COMMON_TIMINGS) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Couldn't find common timings that suit all the displays in this Grid Topology."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_DISPLAY_CONNECTED) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: No display connected."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_EDID_AVAILABLE) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: Your display didn't provide any information when we attempted to query it. Your display either doesn't support support EDID querying or has it a fault. "); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_GPU_TOPOLOGY) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: There is no GPU topology provided."); } else if (topoStatuses[i].ErrorFlags == NV_MOSAIC_DISPLAYCAPS_PROBLEM_FLAGS.NO_SLI_BRIDGE) { SharedLogger.logger.Error($"NVIDIALibrary/SetActiveConfig: Error with the GridTopology #{i}: There is no SLI bridge, and there was one when the display profile was created."); } // And now we also check to see if there are any warnings we also need to log if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.NONE) { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Congratulations! No warning flags for GridTopology #{i}"); } else if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.DISPLAY_POSITION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Warning for the GridTopology #{i}: The display position has changed, and this may affect your display view."); } else if (topoStatuses[i].WarningFlags == NV_MOSAIC_DISPLAYTOPO_WARNING_FLAGS.DRIVER_RELOAD_REQUIRED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Warning for the GridTopology #{i}: Your computer needs to be restarted before your NVIDIA device driver can use this Grid Topology."); } } } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Mosaic is not supported with the existing hardware. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_ACTIVE_SLI_TOPOLOGY) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: No matching GPU topologies could be found. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_TOPO_NOT_POSSIBLE) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The topology passed in is not currently possible. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: One or more argumentss passed in are invalid. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INCOMPATIBLE_STRUCT_VERSION) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The version of the structure passed in is not compatible with this entrypoint. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_MODE_CHANGE_FAILED) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: There was an error changing the display mode. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_Mosaic_ValidateDisplayGrids() returned error code {NVStatus}"); } // Cancel the screen change if there was an error with anything above this. if (topoValid) { // If there was an issue then we need to return false // to indicate that the display profile can't be applied SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: The display settings are valid."); return true; } else { // If there was an issue then we need to return false // to indicate that the display profile can't be applied SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: There was an error when validating the requested grid topology that prevents us from using the display settings provided. THe display setttings are NOT valid."); return false; }*/ } else { // Its not a Mosaic topology, so we just let it pass, as it's windows settings that matter. return true; } } public bool IsPossibleConfig(NVIDIA_DISPLAY_CONFIG displayConfig) { // We want to check the NVIDIA profile can be used now SharedLogger.logger.Trace($"NVIDIALibrary/IsPossibleConfig: Testing whether the NVIDIA display configuration is possible to be used now"); // check what the currently available displays are (include the ones not active) List currentAllIds = GetAllConnectedDisplayIdentifiers(); // CHeck that we have all the displayConfig DisplayIdentifiers we need available now if (displayConfig.DisplayIdentifiers.All(value => currentAllIds.Contains(value))) //if (currentAllIds.Intersect(displayConfig.DisplayIdentifiers).Count() == displayConfig.DisplayIdentifiers.Count) { SharedLogger.logger.Trace($"NVIDIALibrary/IsPossibleConfig: Success! The NVIDIA display configuration is possible to be used now"); return true; } else { SharedLogger.logger.Trace($"NVIDIALibrary/IsPossibleConfig: Uh oh! The NVIDIA display configuration is possible cannot be used now"); return false; } } public List GetCurrentDisplayIdentifiers() { SharedLogger.logger.Error($"NVIDIALibrary/GetCurrentDisplayIdentifiers: Getting the current display identifiers for the displays in use now"); return GetSomeDisplayIdentifiers(false); } public List GetAllConnectedDisplayIdentifiers() { SharedLogger.logger.Error($"NVIDIALibrary/GetAllConnectedDisplayIdentifiers: Getting all the display identifiers that can possibly be used"); return GetSomeDisplayIdentifiers(true); } private List GetSomeDisplayIdentifiers(bool allDisplays = true) { SharedLogger.logger.Debug($"NVIDIALibrary/GetCurrentDisplayIdentifiers: Generating the unique Display Identifiers for the currently active configuration"); List displayIdentifiers = new List(); // Enumerate all the Physical GPUs PhysicalGpuHandle[] physicalGpus = new PhysicalGpuHandle[NVImport.NV_MAX_PHYSICAL_GPUS]; uint physicalGpuCount = 0; NVAPI_STATUS NVStatus = NVImport.NvAPI_EnumPhysicalGPUs(ref physicalGpus, out physicalGpuCount); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_EnumPhysicalGPUs returned {physicalGpuCount} Physical GPUs"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Error getting physical GPU count. NvAPI_EnumPhysicalGPUs() returned error code {NVStatus}"); } // Go through the Physical GPUs one by one for (uint physicalGpuIndex = 0; physicalGpuIndex < physicalGpuCount; physicalGpuIndex++) { //We want to get the name of the physical device string gpuName = ""; NVStatus = NVImport.NvAPI_GPU_GetFullName(physicalGpus[physicalGpuIndex], ref gpuName); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetFullName returned OK. The GPU Full Name is {gpuName}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting the GPU full name! NvAPI_GPU_GetFullName() returned error code {NVStatus}"); } //We want to get the physical details of the physical device NV_GPU_BUS_TYPE busType = NV_GPU_BUS_TYPE.UNDEFINED; NVStatus = NVImport.NvAPI_GPU_GetBusType(physicalGpus[physicalGpuIndex], ref busType); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetBoardInfo returned OK. THe GPU BusType is {busType.ToString("G")}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_GPU_GetBoardInfo() returned error code {NVStatus}"); } //We want to get the physical details of the physical device UInt32 busId = 0; NVStatus = NVImport.NvAPI_GPU_GetBusId(physicalGpus[physicalGpuIndex], ref busId); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetBusId returned OK. The GPU Bus ID was {busId}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Mosaic is not supported with the existing hardware. NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: One or more argumentss passed in are invalid. NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_GPU_GetBusId() returned error code {NVStatus}"); } // Next, we need to get all the connected Display IDs. //This function retrieves the number of display IDs we know about UInt32 displayCount = 0; NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayCount, 0); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_DISP_GetGDIPrimaryDisplayId returned OK. We have {displayCount} connected displays detected."); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } if (displayCount > 0) { // Now we try to get the information about the displayIDs NV_GPU_DISPLAYIDS_V2[] displayIds = new NV_GPU_DISPLAYIDS_V2[displayCount]; NVStatus = NVImport.NvAPI_GPU_GetConnectedDisplayIds(physicalGpus[physicalGpuIndex], ref displayIds, ref displayCount, 0); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetConnectedDisplayIds returned OK. We have {displayCount} physical GPUs"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_DISP_GetGDIPrimaryDisplayId() returned error code {NVStatus}"); } // Now, we want to go through the displays foreach (NV_GPU_DISPLAYIDS_V2 oneDisplay in displayIds) { // If alldisplays is false, then we only want the active displays. We need to skip this one if it is not active if (allDisplays == false && oneDisplay.IsActive == false) { // We want to skip this display as it is non-active, and we only want active displays continue; } // Now we try to get the GPU and Output ID from the DisplayID PhysicalGpuHandle physicalGpu = new PhysicalGpuHandle(); UInt32 gpuOutputId = 0; NVStatus = NVImport.NvAPI_SYS_GetGpuAndOutputIdFromDisplayId(oneDisplay.DisplayId, out physicalGpu, out gpuOutputId); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_SYS_GetGpuAndOutputIdFromDisplayId returned OK. We received Physical GPU ID {physicalGpu} and GPU Output ID {gpuOutputId}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input buffer is not large enough to hold it's contents. NvAPI_SYS_GetGpuAndOutputIdFromDisplayId() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetConnectedDisplayIds() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_SYS_GetGpuAndOutputIdFromDisplayId() returned error code {NVStatus}"); } // Lets set some EDID default in case the EDID doesn't work string manufacturerName = "Unknown"; UInt32 productCode = 0; UInt32 serialNumber = 0; // We try to get an EDID block and extract the info NV_EDID_V3 edidInfo = new NV_EDID_V3(); NVStatus = NVImport.NvAPI_GPU_GetEDID(physicalGpu, gpuOutputId, ref edidInfo); if (NVStatus == NVAPI_STATUS.NVAPI_OK) { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: NvAPI_GPU_GetEDID returned OK. We have got an EDID Block."); EDID edidParsedInfo = new EDID(edidInfo.EDID_Data); manufacturerName = edidParsedInfo.ManufacturerCode; productCode = edidParsedInfo.ProductCode; serialNumber = edidParsedInfo.SerialNumber; } else { if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_ARGUMENT) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: Either edidInfo was null when it was supplied, or gpuOutputId . NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NVIDIA_DEVICE_NOT_FOUND) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: No active GPU was found. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_EXPECTED_PHYSICAL_GPU_HANDLE) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The GPU Handle supplied was not a valid GPU Handle. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_DATA_NOT_FOUND) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The display does not support EDID. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: The NvAPI API needs to be initialized first. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: This entry point not available in this NVIDIA Driver. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR) { SharedLogger.logger.Warn($"NVIDIALibrary/GetNVIDIADisplayConfig: A miscellaneous error occurred. NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } else { SharedLogger.logger.Trace($"NVIDIALibrary/GetNVIDIADisplayConfig: Some non standard error occurred while getting Mosaic Topology! NvAPI_GPU_GetEDID() returned error code {NVStatus}"); } } // Create an array of all the important display info we need to record List displayInfo = new List(); displayInfo.Add("NVIDIA"); try { displayInfo.Add(gpuName.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting GPU Name from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(busType.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting GPU Bus Type from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(busId.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting GPU Bus ID from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(gpuOutputId.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting GPU Output ID from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(manufacturerName.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting NVIDIA EDID Manufacturer Name for the display from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(productCode.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting NVIDIA EDID Product Code for the display from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(serialNumber.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting NVIDIA EDID Serial Number for the display from video card. Substituting with a # instead"); displayInfo.Add("#"); } try { displayInfo.Add(oneDisplay.DisplayId.ToString()); } catch (Exception ex) { SharedLogger.logger.Warn(ex, $"NVIDIALibrary/GetSomeDisplayIdentifiers: Exception getting Display ID from video card. Substituting with a # instead"); displayInfo.Add("#"); } // Create a display identifier out of it string displayIdentifier = String.Join("|", displayInfo); // Add it to the list of display identifiers so we can return it // but only add it if it doesn't already exist. Otherwise we get duplicates :/ if (!displayIdentifiers.Contains(displayIdentifier)) { displayIdentifiers.Add(displayIdentifier); SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}"); } } } } // Sort the display identifiers displayIdentifiers.Sort(); return displayIdentifiers; } } [global::System.Serializable] public class NVIDIALibraryException : Exception { public NVIDIALibraryException() { } public NVIDIALibraryException(string message) : base(message) { } public NVIDIALibraryException(string message, Exception inner) : base(message, inner) { } protected NVIDIALibraryException( System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } }