using System;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.Interfaces.Mosaic;
using NvAPIWrapper.Native.Mosaic;
using NvAPIWrapper.Native.Mosaic.Structures;
namespace NvAPIWrapper.Mosaic
{
///
/// Represents a mosaic grid topology
///
public class GridTopology : IEquatable
{
///
/// Creates a new GridTopology
///
/// Mosaic rows
/// Mosaic columns
/// Topology displays
public GridTopology(int rows, int columns, GridTopologyDisplay[] displays)
{
SetDisplays(rows, columns, displays);
var possibleDisplaySettings = GetPossibleDisplaySettings();
if (possibleDisplaySettings.Any())
{
SetDisplaySettings(
possibleDisplaySettings.OrderByDescending(
settings => (long) settings.Width *
settings.Height *
settings.BitsPerPixel *
settings.Frequency)
.First());
}
}
///
/// Creates a new GridTopology
///
/// A IGridTopology implamented object
public GridTopology(IGridTopology gridTopology)
{
Rows = gridTopology.Rows;
Columns = gridTopology.Columns;
Displays = gridTopology.Displays.Select(display => new GridTopologyDisplay(display)).ToArray();
SetDisplaySettings(gridTopology.DisplaySettings);
ApplyWithBezelCorrectedResolution = gridTopology.ApplyWithBezelCorrectedResolution;
ImmersiveGaming = gridTopology.ImmersiveGaming;
BaseMosaicPanoramic = gridTopology.BaseMosaicPanoramic;
DriverReloadAllowed = gridTopology.DriverReloadAllowed;
AcceleratePrimaryDisplay = gridTopology.AcceleratePrimaryDisplay;
}
///
/// Gets or sets a boolean value enabling SLI acceleration on the primary display while in single-wide mode (For
/// Immersive Gaming only).
///
public bool AcceleratePrimaryDisplay { get; set; }
///
/// Gets or sets a boolean value forcing to the bezel-corrected resolution when enabling and doing the modeset
///
public bool ApplyWithBezelCorrectedResolution { get; set; }
///
/// Gets or sets a boolean value enabling the Base Mosaic (Panoramic) instead of Mosaic SLI (for NVS and Quadro-boards
/// only)
///
public bool BaseMosaicPanoramic { get; set; }
///
/// Gets the mosaic columns
///
public int Columns { get; private set; }
///
/// Gets topology displays
///
public GridTopologyDisplay[] Displays { get; private set; }
///
/// Gets or sets a boolean value allowing the API to, if necessary, realod the driver (for Vista and above only). Will
/// not be persisted. Value undefined on get.
///
public bool DriverReloadAllowed { get; set; }
///
/// Gets the topology Frequency
///
public int Frequency { get; private set; }
///
/// Gets or sets a boolean value enabling as immersive gaming instead of Mosaic SLI (for Quadro-boards only)
///
public bool ImmersiveGaming { get; set; }
///
/// Gets the topology resolution
///
public Resolution Resolution { get; private set; }
///
/// Gets the mosaic rows
///
public int Rows { get; private set; }
///
public bool Equals(GridTopology other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Resolution.Equals(other.Resolution) &&
Frequency == other.Frequency &&
Rows == other.Rows &&
Columns == other.Columns &&
Displays.SequenceEqual(other.Displays) &&
ApplyWithBezelCorrectedResolution == other.ApplyWithBezelCorrectedResolution &&
ImmersiveGaming == other.ImmersiveGaming &&
BaseMosaicPanoramic == other.BaseMosaicPanoramic &&
AcceleratePrimaryDisplay == other.AcceleratePrimaryDisplay;
}
///
/// Retrieves a list of currently active mosaic grid topologies
///
/// An array of GridTopology objects
public static GridTopology[] GetGridTopologies()
{
return MosaicApi.EnumDisplayGrids().Select(topology => new GridTopology(topology)).ToArray();
}
///
/// Checks for equality between two objects of same type
///
/// The first object
/// The second object
/// true, if both objects are equal, otherwise false
public static bool operator ==(GridTopology left, GridTopology right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
///
/// Checks for inequality between two objects of same type
///
/// The first object
/// The second object
/// true, if both objects are not equal, otherwise false
public static bool operator !=(GridTopology left, GridTopology right)
{
return !(left == right);
}
///
/// Applies the requested grid topologies
///
/// An array of grid topologies to apply
/// SetDisplayTopologyFlag flag
public static void SetGridTopologies(
GridTopology[] grids,
SetDisplayTopologyFlag flags = SetDisplayTopologyFlag.NoFlag)
{
var gridTopologyV2 = grids.Select(grid => grid.GetGridTopologyV2()).Cast().ToArray();
try
{
MosaicApi.SetDisplayGrids(gridTopologyV2, flags);
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
var gridTopologyV1 = grids.Select(grid => grid.GetGridTopologyV1()).Cast().ToArray();
MosaicApi.SetDisplayGrids(gridTopologyV1, flags);
}
///
/// Validates a list of grid topologies
///
/// An array of grid topologies to validate
/// SetDisplayTopologyFlag flag
/// An array of DisplayTopologyStatus object containing the result of the validation
public static DisplayTopologyStatus[] ValidateGridTopologies(
GridTopology[] grids,
SetDisplayTopologyFlag flags = SetDisplayTopologyFlag.AllowInvalid)
{
var gridTopologyV2 = grids.Select(grid => grid.GetGridTopologyV2()).Cast().ToArray();
try
{
return MosaicApi.ValidateDisplayGrids(gridTopologyV2, flags);
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
var gridTopologyV1 = grids.Select(grid => grid.GetGridTopologyV1()).Cast().ToArray();
return MosaicApi.ValidateDisplayGrids(gridTopologyV1, flags);
}
///
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((GridTopology) obj);
}
///
public override int GetHashCode()
{
unchecked
{
var hashCode = Resolution.GetHashCode();
hashCode = (hashCode * 397) ^ Frequency;
hashCode = (hashCode * 397) ^ Rows;
hashCode = (hashCode * 397) ^ Columns;
hashCode = (hashCode * 397) ^ (Displays?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ ApplyWithBezelCorrectedResolution.GetHashCode();
hashCode = (hashCode * 397) ^ ImmersiveGaming.GetHashCode();
hashCode = (hashCode * 397) ^ BaseMosaicPanoramic.GetHashCode();
hashCode = (hashCode * 397) ^ AcceleratePrimaryDisplay.GetHashCode();
return hashCode;
}
}
///
/// Creates and fills a DisplaySettingsV1 object
///
/// The newly created DisplaySettingsV1 object
public DisplaySettingsV1 GetDisplaySettingsV1()
{
return new DisplaySettingsV1(Resolution.Width, Resolution.Height, Resolution.ColorDepth, Frequency);
}
///
/// Creates and fills a GridTopologyV1 object
///
/// The newly created GridTopologyV1 object
public GridTopologyV1 GetGridTopologyV1()
{
var displaySettings = GetDisplaySettingsV1();
return new GridTopologyV1(Rows, Columns,
Displays.Select(display => display.GetGridTopologyDisplayV1()).ToArray(), displaySettings,
ApplyWithBezelCorrectedResolution, ImmersiveGaming, BaseMosaicPanoramic, DriverReloadAllowed,
AcceleratePrimaryDisplay);
}
///
/// Creates and fills a GridTopologyV2 object
///
/// The newly created GridTopologyV2 object
public GridTopologyV2 GetGridTopologyV2()
{
var displaySettings = GetDisplaySettingsV1();
return new GridTopologyV2(Rows, Columns,
Displays.Select(display => display.GetGridTopologyDisplayV2()).ToArray(), displaySettings,
ApplyWithBezelCorrectedResolution, ImmersiveGaming, BaseMosaicPanoramic, DriverReloadAllowed,
AcceleratePrimaryDisplay,
Displays.Any(display => display.PixelShiftType != PixelShiftType.NoPixelShift));
}
///
/// Retrieves a list of possible display settings for this topology
///
/// An array of IDisplaySettings implamented objects
public IDisplaySettings[] GetPossibleDisplaySettings()
{
var gridTopologyV2 = GetGridTopologyV2();
try
{
return MosaicApi.EnumDisplayModes(gridTopologyV2);
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
var gridTopologyV1 = GetGridTopologyV1();
return MosaicApi.EnumDisplayModes(gridTopologyV1);
}
///
/// Changes topology arrangement and displays
///
/// Mosaic rows
/// Mosaic columns
/// Topology displays
/// Invalid display arrangement.
/// Number of displays should match the arrangement.
public void SetDisplays(int rows, int columns, GridTopologyDisplay[] displays)
{
if (rows * columns <= 0)
{
throw new ArgumentOutOfRangeException($"{nameof(rows)}, {nameof(columns)}",
"Invalid display arrangement.");
}
if (displays.Length != rows * columns)
{
throw new ArgumentException("Number of displays should match the arrangement.", nameof(displays));
}
Rows = rows;
Columns = columns;
Displays = displays;
}
///
/// Changes display settings for the topology
///
/// Display settings to use
public void SetDisplaySettings(IDisplaySettings displaySettings)
{
Resolution = new Resolution(displaySettings.Width, displaySettings.Height, displaySettings.BitsPerPixel);
Frequency = displaySettings.Frequency;
}
}
}