using System; using System.Linq; using NvAPIWrapper.Native.Exceptions; using NvAPIWrapper.Native.General; using NvAPIWrapper.Native.Helpers; using NvAPIWrapper.Native.Helpers.Structures; using NvAPIWrapper.Native.Interfaces.Mosaic; using NvAPIWrapper.Native.Mosaic; using NvAPIWrapper.Native.Mosaic.Structures; namespace NvAPIWrapper.Native { /// /// Contains mosaic and topology static functions /// public static class MosaicApi { /// /// This API enables or disables the current Mosaic topology based on the setting of the incoming 'enable' parameter. /// An "enable" setting enables the current (previously set) Mosaic topology. /// Note that when the current Mosaic topology is retrieved, it must have an isPossible value of true or an error will /// occur. /// A "disable" setting disables the current Mosaic topology. /// The topology information will persist, even across reboots. /// To re-enable the Mosaic topology, call this function again with the enable parameter set to true. /// /// true to enable the current Mosaic topo, false to disable it. /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.TopologyNotPossible: The current topology is not currently possible. /// Status.ModeChangeFailed: There was an error changing the display mode. /// Status.Error: Miscellaneous error occurred. public static void EnableCurrentTopology(bool enable) { var status = DelegateFactory.GetDelegate()((uint) (enable ? 1 : 0)); if (status != Status.Ok) { throw new NVIDIAApiException(status); } } /// /// Enumerates the current active grid topologies. This includes Mosaic, IG, and Panoramic topologies, as well as /// single displays. /// /// The list of active grid topologies. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. /// This operation is not supported. /// A delegate callback throws an exception. public static IGridTopology[] EnumDisplayGrids() { var mosaicEnumDisplayGrids = DelegateFactory.GetDelegate(); var totalAvailable = 0u; var status = mosaicEnumDisplayGrids(ValueTypeArray.Null, ref totalAvailable); if (status != Status.Ok) { throw new NVIDIAApiException(status); } if (totalAvailable == 0) { return new IGridTopology[0]; } foreach (var acceptType in mosaicEnumDisplayGrids.Accepts()) { var counts = totalAvailable; var instance = acceptType.Instantiate(); using ( var gridTopologiesByRef = ValueTypeArray.FromArray(instance.Repeat((int) counts).AsEnumerable())) { status = mosaicEnumDisplayGrids(gridTopologiesByRef, ref counts); if (status == Status.IncompatibleStructureVersion) { continue; } if (status != Status.Ok) { throw new NVIDIAApiException(status); } return gridTopologiesByRef.ToArray((int) counts, acceptType); } } throw new NVIDIANotSupportedException("This operation is not supported."); } /// /// Determines the set of available display modes for a given grid topology. /// /// The grid topology to use. /// /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. /// This operation is not supported. /// A delegate callback throws an exception. public static IDisplaySettings[] EnumDisplayModes(IGridTopology gridTopology) { var mosaicEnumDisplayModes = DelegateFactory.GetDelegate(); using (var gridTopologyByRef = ValueTypeReference.FromValueType(gridTopology, gridTopology.GetType())) { var totalAvailable = 0u; var status = mosaicEnumDisplayModes(gridTopologyByRef, ValueTypeArray.Null, ref totalAvailable); if (status != Status.Ok) { throw new NVIDIAApiException(status); } if (totalAvailable == 0) { return new IDisplaySettings[0]; } foreach (var acceptType in mosaicEnumDisplayModes.Accepts(2)) { var counts = totalAvailable; var instance = acceptType.Instantiate(); using ( var displaySettingByRef = ValueTypeArray.FromArray(instance.Repeat((int) counts).AsEnumerable())) { status = mosaicEnumDisplayModes(gridTopologyByRef, displaySettingByRef, ref counts); if (status == Status.IncompatibleStructureVersion) { continue; } if (status != Status.Ok) { throw new NVIDIAApiException(status); } return displaySettingByRef.ToArray((int) counts, acceptType); } } throw new NVIDIANotSupportedException("This operation is not supported."); } } /// /// This API returns information for the current Mosaic topology. /// This includes topology, display settings, and overlap values. /// You can call NvAPI_Mosaic_GetTopoGroup() with the topology if you require more information. /// If there isn't a current topology, then TopologyBrief.Topology will be Topology.None. /// /// The current Mosaic topology /// The current per-display settings /// The pixel overlap between horizontal displays /// The pixel overlap between vertical displays /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. /// This operation is not supported. /// A delegate callback throws an exception. // ReSharper disable once TooManyArguments public static void GetCurrentTopology( out TopologyBrief topoBrief, out IDisplaySettings displaySettings, out int overlapX, out int overlapY) { var mosaicGetCurrentTopo = DelegateFactory.GetDelegate(); topoBrief = typeof(TopologyBrief).Instantiate(); foreach (var acceptType in mosaicGetCurrentTopo.Accepts()) { displaySettings = acceptType.Instantiate(); using (var displaySettingsByRef = ValueTypeReference.FromValueType(displaySettings, acceptType)) { var status = mosaicGetCurrentTopo(ref topoBrief, displaySettingsByRef, out overlapX, out overlapY); if (status == Status.IncompatibleStructureVersion) { continue; } if (status != Status.Ok) { throw new NVIDIAApiException(status); } displaySettings = displaySettingsByRef.ToValueType(acceptType); return; } } throw new NVIDIANotSupportedException("This operation is not supported."); } /// /// This API returns the X and Y overlap limits required if the given Mosaic topology and display settings are to be /// used. /// /// /// The topology for getting limits This must be one of the topo briefs returned from /// GetSupportedTopoInfo(). /// /// /// The display settings for getting the limits. This must be one of the settings returned /// from GetSupportedTopoInfo(). /// /// X overlap minimum /// X overlap maximum /// Y overlap minimum /// Y overlap maximum /// displaySettings is of invalid type. /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. /// A delegate callback throws an exception. // ReSharper disable once TooManyArguments public static void GetOverlapLimits( TopologyBrief topoBrief, IDisplaySettings displaySettings, out int minOverlapX, out int maxOverlapX, out int minOverlapY, out int maxOverlapY) { var mosaicGetOverlapLimits = DelegateFactory.GetDelegate(); if (!mosaicGetOverlapLimits.Accepts().Contains(displaySettings.GetType())) { throw new ArgumentException("Parameter type is not supported.", nameof(displaySettings)); } using ( var displaySettingsByRef = ValueTypeReference.FromValueType(displaySettings, displaySettings.GetType())) { var status = mosaicGetOverlapLimits(topoBrief, displaySettingsByRef, out minOverlapX, out maxOverlapX, out minOverlapY, out maxOverlapY); if (status != Status.Ok) { throw new NVIDIAApiException(status); } } } /// /// This API returns information on the topologies and display resolutions supported by Mosaic mode. /// NOTE: Not all topologies returned can be set immediately. Some of the topologies returned might not be valid for /// one reason or another. It could be due to mismatched or missing displays. It could also be because the required /// number of GPUs is not found. /// Once you get the list of supported topologies, you can call GetTopologyGroup() with one of the Mosaic topologies if /// you need more information about it. /// It is possible for this function to return NVAPI_OK with no topologies listed in the return structure. If this is /// the case, it means that the current hardware DOES support Mosaic, but with the given configuration no valid /// topologies were found. This most likely means that SLI was not enabled for the hardware. Once enabled, you should /// see valid topologies returned from this function. /// /// The type of topologies the caller is interested in getting. /// Information about what topologies and display resolutions are supported for Mosaic. /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: TopologyType is invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry-point not available. /// Status.Error: Miscellaneous error occurred. /// This operation is not supported. /// A delegate callback throws an exception. public static ISupportedTopologiesInfo GetSupportedTopologiesInfo(TopologyType topologyType) { var mosaicGetSupportedTopoInfo = DelegateFactory.GetDelegate(); foreach (var acceptType in mosaicGetSupportedTopoInfo.Accepts()) { var instance = acceptType.Instantiate(); using (var supportedTopologiesInfoByRef = ValueTypeReference.FromValueType(instance, acceptType)) { var status = mosaicGetSupportedTopoInfo(supportedTopologiesInfoByRef, topologyType); if (status == Status.IncompatibleStructureVersion) { continue; } if (status != Status.Ok) { throw new NVIDIAApiException(status); } return supportedTopologiesInfoByRef.ToValueType(acceptType); } } throw new NVIDIANotSupportedException("This operation is not supported."); } /// /// This API returns a structure filled with the details of the specified Mosaic topology. /// If the pTopoBrief passed in matches the current topology, then information in the brief and group structures will /// reflect what is current. Thus the brief would have the current 'enable' status, and the group would have the /// current overlap values. If there is no match, then the returned brief has an 'enable' status of FALSE (since it is /// obviously not enabled), and the overlap values will be 0. /// /// /// The topology for getting the details. This must be one of the topology briefs returned from /// GetSupportedTopoInfo(). /// /// The topology details matching the brief /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. public static TopologyGroup GetTopologyGroup(TopologyBrief topoBrief) { var result = typeof(TopologyGroup).Instantiate(); var status = DelegateFactory.GetDelegate()(topoBrief, ref result); if (status != Status.Ok) { throw new NVIDIAApiException(status); } return result; } /// /// This API sets the Mosaic topology and performs a mode switch using the given display settings. /// /// /// The topology to set. This must be one of the topologies returned from GetSupportedTopoInfo(), /// and it must have an isPossible value of true. /// /// /// The per display settings to be used in the Mosaic mode. This must be one of the settings /// returned from GetSupportedTopoInfo(). /// /// /// The pixel overlap to use between horizontal displays (use positive a number for overlap, or a /// negative number to create a gap.) If the overlap is out of bounds for what is possible given the topo and display /// setting, the overlap will be clamped. /// /// /// The pixel overlap to use between vertical displays (use positive a number for overlap, or a /// negative number to create a gap.) If the overlap is out of bounds for what is possible given the topo and display /// setting, the overlap will be clamped. /// /// /// If true, the topology being set will also be enabled, meaning that the mode set will occur. If /// false, you don't want to be in Mosaic mode right now, but want to set the current Mosaic topology so you can enable /// it later with EnableCurrentTopo() /// /// displaySettings is of invalid type. /// Status.NotSupported: Mosaic is not supported with the existing hardware. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. /// A delegate callback throws an exception. // ReSharper disable once TooManyArguments public static void SetCurrentTopology( TopologyBrief topoBrief, IDisplaySettings displaySettings, int overlapX, int overlapY, bool enable) { var mosaicSetCurrentTopo = DelegateFactory.GetDelegate(); if (!mosaicSetCurrentTopo.Accepts().Contains(displaySettings.GetType())) { throw new ArgumentException("Parameter type is not supported.", nameof(displaySettings)); } using ( var displaySettingsByRef = ValueTypeReference.FromValueType(displaySettings, displaySettings.GetType())) { var status = mosaicSetCurrentTopo(topoBrief, displaySettingsByRef, overlapX, overlapY, (uint) (enable ? 1 : 0)); if (status != Status.Ok) { throw new NVIDIAApiException(status); } } } /// /// Sets a new display topology, replacing any existing topologies that use the same displays. /// This function will look for an SLI configuration that will allow the display topology to work. /// To revert to a single display, specify that display as a 1x1 grid. /// /// The topology details to set. /// One of the SetDisplayTopologyFlag flags /// Status.TopologyNotPossible: One or more of the display grids are not valid. /// Status.NoActiveSLITopology: No matching GPU topologies could be found. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. public static void SetDisplayGrids( IGridTopology[] gridTopologies, SetDisplayTopologyFlag flags = SetDisplayTopologyFlag.NoFlag) { using (var gridTopologiesByRef = ValueTypeArray.FromArray(gridTopologies.AsEnumerable())) { var status = DelegateFactory.GetDelegate()(gridTopologiesByRef, (uint) gridTopologies.Length, flags); if (status != Status.Ok) { throw new NVIDIAApiException(status); } } } /// /// Determines if a list of grid topologies is valid. It will choose an SLI configuration in the same way that /// SetDisplayGrids() does. /// On return, each element in the pTopoStatus array will contain any errors or warnings about each grid topology. If /// any error flags are set, then the topology is not valid. If any warning flags are set, then the topology is valid, /// but sub-optimal. /// If the ALLOW_INVALID flag is set, then it will continue to validate the grids even if no SLI configuration will /// allow all of the grids. In this case, a grid grid with no matching GPU topology will have the error flags /// NO_GPU_TOPOLOGY or NOT_SUPPORTED set. /// If the ALLOW_INVALID flag is not set and no matching SLI configuration is found, then it will skip the rest of the /// validation and throws a NVIDIAApiException with Status.NoActiveSLITopology. /// /// The array of grid topologies to verify. /// One of the SetDisplayTopologyFlag flags /// Status.NoActiveSLITopology: No matching GPU topologies could be found. /// Status.InvalidArgument: One or more arguments passed in are invalid. /// Status.ApiNotInitialized: The NvAPI API needs to be initialized first. /// Status.NoImplementation: This entry point not available. /// Status.Error: Miscellaneous error occurred. public static DisplayTopologyStatus[] ValidateDisplayGrids( IGridTopology[] gridTopologies, SetDisplayTopologyFlag flags = SetDisplayTopologyFlag.NoFlag) { using (var gridTopologiesByRef = ValueTypeArray.FromArray(gridTopologies.AsEnumerable())) { var statuses = typeof(DisplayTopologyStatus).Instantiate().Repeat(gridTopologies.Length); var status = DelegateFactory.GetDelegate()(flags, gridTopologiesByRef, ref statuses, (uint) gridTopologies.Length); if (status != Status.Ok) { throw new NVIDIAApiException(status); } return statuses; } } } }