Updated NVIDIA, AMD and Windows Video libraries

Updated with enhancements to make application of colour more robust, and to avoid a Windows CCD display validation issue.
This commit is contained in:
Terry MacDonald 2021-11-13 15:06:54 +13:00
parent 2b653999dd
commit d4494aa699
4 changed files with 972 additions and 527 deletions

View File

@ -1336,13 +1336,11 @@ namespace DisplayMagicianShared.AMD
// We need to change to an Eyefinity (SLS) profile, so we need to apply the new SLS Topologies
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SLS is enabled in the new display configuration, so we need to set it");
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: There are {displayConfig.SlsConfig.SLSMapConfigs.Count} SLSMapConfigs in this display configuration");
foreach (AMD_SLSMAP_CONFIG slsMapConfig in displayConfig.SlsConfig.SLSMapConfigs)
{
// Attempt to turn on this SLS Map Config if it exists in the AMD Radeon driver config database
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap.SLSMapIndex, ADLImport.ADL_TRUE);
if (ADLRet == ADL_STATUS.ADL_OK || ADLRet == ADL_STATUS.ADL_OK_MODE_CHANGE || ADLRet == ADL_STATUS.ADL_OK_RESTART || ADLRet == ADL_STATUS.ADL_OK_WAIT || ADLRet == ADL_STATUS.ADL_OK_WARNING)
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully set the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} to TRUE for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
}
@ -1360,7 +1358,7 @@ namespace DisplayMagicianShared.AMD
int supportedSLSLayoutImageMode;
int reasonForNotSupportSLS;
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_Valid(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap, slsMapConfig.SLSTargets.Count, slsMapConfig.SLSTargets.ToArray(), out supportedSLSLayoutImageMode, out reasonForNotSupportSLS, ADLImport.ADL_DISPLAY_SLSMAPCONFIG_CREATE_OPTION_RELATIVETO_CURRENTANGLE);
if (ADLRet == ADL_STATUS.ADL_OK || ADLRet == ADL_STATUS.ADL_OK_MODE_CHANGE || ADLRet == ADL_STATUS.ADL_OK_RESTART || ADLRet == ADL_STATUS.ADL_OK_WAIT || ADLRet == ADL_STATUS.ADL_OK_WARNING)
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_Valid successfully validated a new SLSMAP config for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
}
@ -1373,7 +1371,7 @@ namespace DisplayMagicianShared.AMD
// Create and apply the new SLSMap
int newSlsMapIndex;
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_Create(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap, slsMapConfig.SLSTargets.Count, slsMapConfig.SLSTargets.ToArray(), slsMapConfig.BezelModePercent, out newSlsMapIndex, ADLImport.ADL_DISPLAY_SLSMAPCONFIG_CREATE_OPTION_RELATIVETO_CURRENTANGLE);
if (ADLRet == ADL_STATUS.ADL_OK || ADLRet == ADL_STATUS.ADL_OK_MODE_CHANGE || ADLRet == ADL_STATUS.ADL_OK_RESTART || ADLRet == ADL_STATUS.ADL_OK_WAIT || ADLRet == ADL_STATUS.ADL_OK_WARNING)
if (ADLRet == ADL_STATUS.ADL_OK)
{
if (newSlsMapIndex != -1)
{
@ -1411,7 +1409,7 @@ namespace DisplayMagicianShared.AMD
{
// Turn off this SLS Map Config
ADLRet = ADLImport.ADL2_Display_SLSMapConfig_SetState(_adlContextHandle, slsMapConfig.SLSMap.AdapterIndex, slsMapConfig.SLSMap.SLSMapIndex, ADLImport.ADL_FALSE);
if (ADLRet == ADL_STATUS.ADL_OK || ADLRet == ADL_STATUS.ADL_OK_MODE_CHANGE || ADLRet == ADL_STATUS.ADL_OK_RESTART || ADLRet == ADL_STATUS.ADL_OK_WAIT || ADLRet == ADL_STATUS.ADL_OK_WARNING)
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: ADL2_Display_SLSMapConfig_SetState successfully disabled the SLSMAP with index {slsMapConfig.SLSMap.SLSMapIndex} for adapter { slsMapConfig.SLSMap.AdapterIndex}.");
}
@ -1423,10 +1421,6 @@ namespace DisplayMagicianShared.AMD
}
}
else
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfig: SLS is not used in the wanted display configuration, or the current display configuration. Nothing to do.");
}
}
@ -1457,34 +1451,42 @@ namespace DisplayMagicianShared.AMD
// Try and find the HDR config displays in the list of currently connected displays
foreach (var displayInfoItem in ActiveDisplayConfig.DisplayTargets)
{
// If we find the HDR config display in the list of currently connected displays then try to set the HDR setting we recorded earlier
if (hdrConfig.Key == displayInfoItem.DisplayID.DisplayLogicalIndex)
try
{
if (hdrConfig.Value.HDREnabled)
// If we find the HDR config display in the list of currently connected displays then try to set the HDR setting we recorded earlier
if (hdrConfig.Key == displayInfoItem.DisplayID.DisplayLogicalIndex)
{
ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 1);
if (ADLRet == ADL_STATUS.ADL_OK)
if (hdrConfig.Value.HDREnabled)
{
SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 1);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfigOverride: ADL2_Display_HDRState_Set was able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
else
{
SharedLogger.logger.Error($"AMDLibrary/SetActiveConfigOverride: ADL2_Display_HDRState_Set was NOT able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
}
else
{
SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was NOT able to turn on HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 0);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/SetActiveConfigOverride: ADL2_Display_HDRState_Set was able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
else
{
SharedLogger.logger.Error($"AMDLibrary/SetActiveConfigOverride: ADL2_Display_HDRState_Set was NOT able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
}
break;
}
else
{
ADLRet = ADLImport.ADL2_Display_HDRState_Set(_adlContextHandle, hdrConfig.Value.AdapterIndex, displayInfoItem.DisplayID, 0);
if (ADLRet == ADL_STATUS.ADL_OK)
{
SharedLogger.logger.Trace($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
else
{
SharedLogger.logger.Error($"AMDLibrary/GetAMDDisplayConfig: ADL2_Display_HDRState_Set was NOT able to turn off HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
}
}
break;
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"AMDLibrary/GetAMDDisplayConfig: Exception! ADL2_Display_HDRState_Set was NOT able to change HDR for display {displayInfoItem.DisplayID.DisplayLogicalIndex}.");
continue;
}
}
@ -1907,7 +1909,7 @@ namespace DisplayMagicianShared.AMD
if (!displayIdentifiers.Contains(displayIdentifier))
{
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"AMDLibrary/GetSomeDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}
}

View File

@ -364,6 +364,72 @@ namespace DisplayMagicianShared.NVIDIA
UNKNOWN = 0xFFFFFFFF,
}
public enum NV_DISPLAYCONFIG_SPANNING_ORIENTATION : UInt32
{
NV_DISPLAYCONFIG_SPAN_NONE = 0,
NV_DISPLAYCONFIG_SPAN_HORIZONTAL = 1,
NV_DISPLAYCONFIG_SPAN_VERTICAL = 2,
}
public enum TIMING_SCAN_MODE : ushort
{
/// <summary>
/// Progressive scan mode
/// </summary>
Progressive = 0,
/// <summary>
/// Interlaced scan mode
/// </summary>
Interlaced = 1,
/// <summary>
/// Interlaced scan mode with extra vertical blank
/// </summary>
InterlacedWithExtraVerticalBlank = 1,
/// <summary>
/// Interlaced scan mode without extra vertical blank
/// </summary>
InterlacedWithNoExtraVerticalBlank = 2
}
public enum TIMING_VERTICAL_SYNC_POLARITY : byte
{
/// <summary>
/// Positive vertical synchronized polarity
/// </summary>
Positive = 0,
/// <summary>
/// Negative vertical synchronized polarity
/// </summary>
Negative = 1,
/// <summary>
/// Default vertical synchronized polarity
/// </summary>
Default = Positive
}
public enum TIMING_HORIZONTAL_SYNC_POLARITY : byte
{
/// <summary>
/// Positive horizontal synchronized polarity
/// </summary>
Positive = 0,
/// <summary>
/// Negative horizontal synchronized polarity
/// </summary>
Negative = 1,
/// <summary>
/// Default horizontal synchronized polarity
/// </summary>
Default = Negative
}
public enum NV_TIMING_OVERRIDE : UInt32
{
CURRENT = 0, //!< get the current timing
@ -822,36 +888,39 @@ namespace DisplayMagicianShared.NVIDIA
}
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)]
public struct NV_TIMINGEXT : IEquatable<NV_TIMINGEXT>
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Ansi)]
public struct NV_TIMING_EXTRA : IEquatable<NV_TIMING_EXTRA>
{
public UInt32 Flag; //!< Reserved for NVIDIA hardware-based enhancement, such as double-scan.
public ushort Rr; //!< Logical refresh rate to present
public UInt32 Rrx1k; //!< Physical vertical refresh rate in 0.001Hz
public UInt32 Aspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
public ushort Rep; //!< Bit-wise pixel repetition factor: 0x1:no pixel repetition; 0x2:each pixel repeats twice horizontally,..
public UInt32 Status; //!< Timing standard
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (Int32)NVImport.NVAPI_UNICODE_STRING_MAX)]
public UInt32 Flags; //!< Reserved for NVIDIA hardware-based enhancement, such as double-scan.
public ushort RefreshRate; //!< Logical refresh rate to present
public UInt32 FrequencyInMillihertz; //!< Physical vertical refresh rate in 0.001Hz
public ushort VerticalAspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
public ushort HorizontalAspect; //!< Display aspect ratio Hi(aspect):horizontal-aspect, Low(aspect):vertical-aspect
public ushort HorizontalPixelRepetition; //!< Bit-wise pixel repetition factor: 0x1:no pixel repetition; 0x2:each pixel repeats twice horizontally,..
public UInt32 TimingStandard; //!< Timing standard
//[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 40)]
public string Name; //!< Timing name
public override bool Equals(object obj) => obj is NV_TIMINGEXT other && this.Equals(other);
public override bool Equals(object obj) => obj is NV_TIMING_EXTRA other && this.Equals(other);
public bool Equals(NV_TIMINGEXT other)
=> Flag == other.Flag &&
Rr == other.Rr &&
Rrx1k == other.Rrx1k &&
Aspect == other.Aspect &&
Rep == other.Rep &&
Status == other.Status &&
public bool Equals(NV_TIMING_EXTRA other)
=> Flags == other.Flags &&
RefreshRate == other.RefreshRate &&
FrequencyInMillihertz == other.FrequencyInMillihertz &&
VerticalAspect == other.VerticalAspect &&
HorizontalAspect == other.HorizontalAspect &&
HorizontalPixelRepetition == other.HorizontalPixelRepetition &&
TimingStandard == other.TimingStandard &&
Name == other.Name;
public override Int32 GetHashCode()
{
return (Flag, Rr, Rrx1k, Aspect, Rep, Status, Name).GetHashCode();
return (Flags, RefreshRate, FrequencyInMillihertz, HorizontalAspect, HorizontalPixelRepetition, TimingStandard, Name).GetHashCode();
}
public static bool operator ==(NV_TIMINGEXT lhs, NV_TIMINGEXT rhs) => lhs.Equals(rhs);
public static bool operator ==(NV_TIMING_EXTRA lhs, NV_TIMING_EXTRA rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_TIMINGEXT lhs, NV_TIMINGEXT rhs) => !(lhs == rhs);
public static bool operator !=(NV_TIMING_EXTRA lhs, NV_TIMING_EXTRA rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
@ -863,20 +932,20 @@ namespace DisplayMagicianShared.NVIDIA
public ushort HFrontPorch; //!< horizontal front porch
public ushort HSyncWidth; //!< horizontal sync width
public ushort HTotal; //!< horizontal total
public byte HSyncPol; //!< horizontal sync polarity: 1-negative, 0-positive
public TIMING_HORIZONTAL_SYNC_POLARITY HSyncPol; //!< horizontal sync polarity: 1-negative, 0-positive
public ushort VVisible; //!< vertical visible
public ushort VBorder; //!< vertical border
public ushort VFrontPorch; //!< vertical front porch
public ushort VSyncWidth; //!< vertical sync width
public ushort VTotal; //!< vertical total
public byte VSyncPol; //!< vertical sync polarity: 1-negative, 0-positive
public TIMING_VERTICAL_SYNC_POLARITY VSyncPol; //!< vertical sync polarity: 1-negative, 0-positive
public ushort Interlaced; //!< 1-Int32erlaced, 0-progressive
public TIMING_SCAN_MODE ScanMode; //!< 1-Int32erlaced, 0-progressive
public UInt32 Pclk; //!< pixel clock in 10 kHz
//other timing related extras
NV_TIMINGEXT Etc;
public NV_TIMING_EXTRA Extra;
public override bool Equals(object obj) => obj is NV_TIMING other && this.Equals(other);
@ -893,13 +962,13 @@ namespace DisplayMagicianShared.NVIDIA
VSyncWidth == other.VSyncWidth &&
VTotal == other.VTotal &&
VSyncPol == other.VSyncPol &&
Interlaced == other.Interlaced &&
ScanMode == other.ScanMode &&
Pclk == other.Pclk &&
Etc.Equals(other.Etc);
Extra.Equals(other.Extra);
public override Int32 GetHashCode()
{
return (HVisible, HBorder, HFrontPorch, HSyncWidth, HTotal, HSyncPol, VVisible, VBorder, VFrontPorch, VSyncWidth, VTotal, VSyncPol, Interlaced, Pclk, Etc).GetHashCode();
return (HVisible, HBorder, HFrontPorch, HSyncWidth, HTotal, HSyncPol, VVisible, VBorder, VFrontPorch, VSyncWidth, VTotal, VSyncPol, ScanMode, Pclk, Extra).GetHashCode();
}
public static bool operator ==(NV_TIMING lhs, NV_TIMING rhs) => lhs.Equals(rhs);
@ -931,6 +1000,27 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator !=(NV_RECT lhs, NV_RECT rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct NV_LUID : IEquatable<NV_LUID>
{
public UInt32 LowPart;
public UInt32 HighPart;
public override bool Equals(object obj) => obj is NV_LUID other && this.Equals(other);
public bool Equals(NV_LUID other)
=> LowPart == other.LowPart &&
HighPart == other.HighPart;
public override Int32 GetHashCode()
{
return (LowPart, HighPart).GetHashCode();
}
public static bool operator ==(NV_LUID lhs, NV_LUID rhs) => lhs.Equals(rhs);
public static bool operator !=(NV_LUID lhs, NV_LUID rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct NV_POSITION : IEquatable<NV_POSITION>
@ -985,6 +1075,14 @@ namespace DisplayMagicianShared.NVIDIA
public float W; //!< Width of the viewport
public float H; //!< Height of the viewport
public NV_VIEWPORTF(float myX, float myY, float myW, float myH) : this()
{
X = myX;
Y = myY;
W = myW;
H = myH;
}
public override bool Equals(object obj) => obj is NV_VIEWPORTF other && this.Equals(other);
// NOTE: Using Math.Round for equality testing between floats.
@ -1018,20 +1116,21 @@ namespace DisplayMagicianShared.NVIDIA
public NV_SCALING Scaling; //!< (IN) scaling setting.
// Refresh Rate
public UInt32 RefreshRate1K; //!< (IN) Non-Int32erlaced Refresh Rate of the mode, multiplied by 1000, 0 = ignored
//!< This is the value which driver reports to the OS.
// Flags
//public UInt32 Int32erlaced:1; //!< (IN) Interlaced mode flag, ignored if refreshRate == 0
//public UInt32 primary:1; //!< (IN) Declares primary display in clone configuration. This is *NOT* GDI Primary.
//!< Only one target can be primary per source. If no primary is specified, the first
//!< target will automatically be primary.
//public UInt32 isPanAndScanTarget:1; //!< Whether on this target Pan and Scan is enabled or has to be enabled. Valid only
//!< when the target is part of clone topology.
//public UInt32 disableVirtualModeSupport:1;
//public UInt32 isPreferredUnscaledTarget:1;
//public UInt32 reserved:27;
// TV format information
public NV_GPU_CONNECTOR_TYPE Connector; //!< Specify connector type. For TV only, ignored if tvFormat == NV_DISPLAY_TV_FORMAT_NONE
public UInt32 RefreshRateInMillihertz; //!< (IN) Non-Int32erlaced Refresh Rate of the mode, multiplied by 1000, 0 = ignored
//!< This is the value which driver reports to the OS.
// Flags
//public UInt32 Int32erlaced:1; //!< (IN) Interlaced mode flag, ignored if refreshRate == 0
//public UInt32 primary:1; //!< (IN) Declares primary display in clone configuration. This is *NOT* GDI Primary.
//!< Only one target can be primary per source. If no primary is specified, the first
//!< target will automatically be primary.
//public UInt32 isPanAndScanTarget:1; //!< Whether on this target Pan and Scan is enabled or has to be enabled. Valid only
//!< when the target is part of clone topology.
//public UInt32 disableVirtualModeSupport:1;
//public UInt32 isPreferredUnscaledTarget:1;
//public UInt32 reserved:27;
public UInt32 Flags;
// TV format information
public NV_GPU_CONNECTOR_TYPE ConnectorType; //!< Specify connector type. For TV only, ignored if tvFormat == NV_DISPLAY_TV_FORMAT_NONE
public NV_DISPLAY_TV_FORMAT TvFormat; //!< (IN) to choose the last TV format set this value to NV_DISPLAY_TV_FORMAT_NONE
//!< In case of NvAPI_DISP_GetDisplayConfig(), this field will indicate the currently applied TV format;
//!< if no TV format is applied, this field will have NV_DISPLAY_TV_FORMAT_NONE value.
@ -1050,15 +1149,16 @@ namespace DisplayMagicianShared.NVIDIA
=> Version == other.Version &&
Rotation == other.Rotation &&
Scaling == other.Scaling &&
RefreshRate1K == other.RefreshRate1K &&
Connector == other.Connector &&
RefreshRateInMillihertz == other.RefreshRateInMillihertz &&
Flags == other.Flags &&
ConnectorType == other.ConnectorType &&
TvFormat == other.TvFormat &&
TimingOverride == other.TimingOverride &&
Timing.Equals(other.Timing);
public override Int32 GetHashCode()
{
return (Version, Rotation, Scaling, RefreshRate1K, Connector, TvFormat, TimingOverride, Timing).GetHashCode();
return (Version, Rotation, Scaling, RefreshRateInMillihertz, Flags, ConnectorType, TvFormat, TimingOverride, Timing).GetHashCode();
}
public static bool operator ==(NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO lhs, NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO rhs) => lhs.Equals(rhs);
@ -1069,19 +1169,19 @@ namespace DisplayMagicianShared.NVIDIA
public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 : IEquatable<NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2>
{
public UInt32 DisplayId; //!< Display ID
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
public UInt32 TargetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
public UInt32 WindowsCCDTargetId; //!< Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is ignored.
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 other && this.Equals(other);
public bool Equals(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 other)
=> DisplayId == other.DisplayId &&
Details.Equals(other.Details) &&
TargetId == other.TargetId;
WindowsCCDTargetId == other.WindowsCCDTargetId;
public override Int32 GetHashCode()
{
return (DisplayId, Details, TargetId).GetHashCode();
return (DisplayId, Details, WindowsCCDTargetId).GetHashCode();
}
public static bool operator ==(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2 rhs) => lhs.Equals(rhs);
@ -1092,7 +1192,7 @@ namespace DisplayMagicianShared.NVIDIA
public struct NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 : IEquatable<NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1>
{
public UInt32 DisplayId; //!< Display ID
NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
public NV_DISPLAYCONFIG_PATH_ADVANCED_TARGET_INFO Details; //!< May be NULL if no advanced settings are required
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 other && this.Equals(other);
@ -1109,23 +1209,26 @@ namespace DisplayMagicianShared.NVIDIA
public static bool operator !=(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 lhs, NV_DISPLAYCONFIG_PATH_TARGET_INFO_V1 rhs) => !(lhs == rhs);
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct NV_DISPLAYCONFIG_PATH_INFO_V2 : IEquatable<NV_DISPLAYCONFIG_PATH_INFO_V2> // Version is 2
{
public UInt32 Version;
public UInt32 SourceId; //!< Identifies sourceId used by Windows CCD. This can be optionally set.
public UInt32 TargetInfoCount; //!< Number of elements in targetInfo array
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2[] TargetInfo;
public NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 SourceModeInfo; //!< May be NULL if mode info is not important
//public UInt32 IsNonNVIDIAAdapter : 1; //!< True for non-NVIDIA adapter.
//public UInt32 reserved : 31; //!< Must be 0
//public LUID pOSAdapterID; //!< Used by Non-NVIDIA adapter for poInt32er to OS Adapter of LUID
//!< type, type casted to void *.
public UInt32 Reserved;
//[MarshalAs(UnmanagedType.ByValArray)]
public IntPtr TargetInfo;
public IntPtr SourceModeInfo; //!< May be NULL if mode info is not important
//public IntPtr SourceModeInfo; //!< May be NULL if mode info is not important
//public UInt32 IsNonNVIDIAAdapter : 1; //!< True for non-NVIDIA adapter.
//public UInt32 reserved : 31; //!< Must be 0
public UInt32 Flags;
//!< Used by Non-NVIDIA adapter for pointer to OS Adapter of LUID
//!< type, type casted to void *.
public IntPtr OSAdapterID;
public bool IsNonNVIDIAAdapter => Flags.GetBit(0); //!< if bit is set then this path uses a non-nvidia adapter
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_PATH_INFO_V2 other && this.Equals(other);
public bool Equals(NV_DISPLAYCONFIG_PATH_INFO_V2 other)
@ -1134,12 +1237,11 @@ namespace DisplayMagicianShared.NVIDIA
TargetInfoCount == other.TargetInfoCount &&
TargetInfo.Equals(other.TargetInfo) &&
SourceModeInfo.Equals(other.SourceModeInfo) &&
Reserved == other.Reserved &&
OSAdapterID == other.OSAdapterID;
Flags == other.Flags;
public override Int32 GetHashCode()
{
return (Version, SourceId, TargetInfoCount, TargetInfo, SourceModeInfo).GetHashCode();
return (Version, SourceId, TargetInfoCount, TargetInfo, SourceModeInfo, Flags).GetHashCode();
}
public static bool operator ==(NV_DISPLAYCONFIG_PATH_INFO_V2 lhs, NV_DISPLAYCONFIG_PATH_INFO_V2 rhs) => lhs.Equals(rhs);
@ -1188,10 +1290,11 @@ namespace DisplayMagicianShared.NVIDIA
public NV_POSITION Position; //!< Is all positions are 0 or invalid, displays will be automatically
//!< positioned from left to right with GDI Primary at 0,0, and all
//!< other displays in the order of the path array.
//public NV_DISPLAYCONFIG_SPANNING_ORIENTATION spanningOrientation; //!< Spanning is only supported on XP
//public UInt32 bGDIPrimary : 1;
//public UInt32 bSLIFocus : 1;
//public UInt32 reserved : 30; //!< Must be 0
public NV_DISPLAYCONFIG_SPANNING_ORIENTATION SpanningOrientation; //!< Spanning is only supported on XP
public UInt32 Flags;
public bool IsGDIPrimary => (Flags & 0x1) == 0x1; //!< if bit is set then this source is the primary GDI source
public bool IsSLIFocus => (Flags & 0x2) == 0x2; //!< if bit is set then this source has SLI focus
public override bool Equals(object obj) => obj is NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 other && this.Equals(other);
@ -2083,6 +2186,7 @@ namespace DisplayMagicianShared.NVIDIA
public static UInt32 NV_EDID_V3_VER = MAKE_NVAPI_VERSION<NV_EDID_V3>(3);
public static UInt32 NV_DISPLAYCONFIG_PATH_INFO_V1_VER = MAKE_NVAPI_VERSION<NV_DISPLAYCONFIG_PATH_INFO_V1>(1);
public static UInt32 NV_DISPLAYCONFIG_PATH_INFO_V2_VER = MAKE_NVAPI_VERSION<NV_DISPLAYCONFIG_PATH_INFO_V2>(2);
public static UInt32 NV_CUSTOM_DISPLAY_V1_VER = MAKE_NVAPI_VERSION<NV_CUSTOM_DISPLAY_V1>(1);
#region Internal Constant
@ -2217,9 +2321,10 @@ namespace DisplayMagicianShared.NVIDIA
GetDelegate(NvId_Disp_GetHdrCapabilities, out Disp_GetHdrCapabilitiesInternal);
GetDelegate(NvId_Disp_HdrColorControl, out Disp_HdrColorControlInternal);
GetDelegate(NvId_Disp_ColorControl, out Disp_ColorControlInternal);
/*GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternal);
GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternalNull); // null version of the submission*/
GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternal);
GetDelegate(NvId_DISP_GetDisplayConfig, out DISP_GetDisplayConfigInternalNull); // null version of the submission
GetDelegate(NvId_DISP_GetDisplayIdByDisplayName, out DISP_GetDisplayIdByDisplayNameInternal);
GetDelegate(NvId_DISP_EnumCustomDisplay, out Disp_EnumCustomDisplayInternal);
// GPUs
GetDelegate(NvId_EnumPhysicalGPUs, out EnumPhysicalGPUsInternal);
@ -3271,152 +3376,180 @@ namespace DisplayMagicianShared.NVIDIA
// ******** IMPORTANT! This code has an error when attempting to perform the third pass as required by NVAPI documentation *********
// ******** FOr this reason I have disabled the code as I don't actually need to get it going. ********
/* // NVAPI_INTERFACE NvAPI_DISP_GetDisplayConfig(__inout NvU32 *pathInfoCount, __out_ecount_full_opt(*pathInfoCount) NV_DISPLAYCONFIG_PATH_INFO *pathInfo);
private delegate NVAPI_STATUS DISP_GetDisplayConfigDelegate(
[In][Out] ref UInt32 pathInfoCount,
[In][Out] IntPtr pathInfoBuffer);
private static readonly DISP_GetDisplayConfigDelegate DISP_GetDisplayConfigInternal;
// NVAPI_INTERFACE NvAPI_DISP_GetDisplayConfig(__inout NvU32 *pathInfoCount, __out_ecount_full_opt(*pathInfoCount) NV_DISPLAYCONFIG_PATH_INFO *pathInfo);
private delegate NVAPI_STATUS DISP_GetDisplayConfigDelegate(
[In][Out] ref UInt32 pathInfoCount,
[In][Out] IntPtr pathInfoBuffer);
private static readonly DISP_GetDisplayConfigDelegate DISP_GetDisplayConfigInternal;
/// <summary>
/// DESCRIPTION: This API lets caller retrieve the current global display configuration.
/// USAGE: The caller might have to call this three times to fetch all the required configuration details as follows:
/// First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set to NULL to fetch pathInfoCount.
/// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch
/// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
/// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
// to number of targetInfoCount(from Second Pass).
/// SUPPORTED OS: Windows 7 and higher
/// </summary>
/// <param name="PathInfoCount"></param>
/// <param name="PathInfo"></param>
/// <returns></returns>
public static NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref UInt32 PathInfoCount, ref NV_DISPLAYCONFIG_PATH_INFO_V1[] PathInfos, bool partFilledIn = false)
/// <summary>
/// DESCRIPTION: This API lets caller retrieve the current global display configuration.
/// USAGE: The caller might have to call this three times to fetch all the required configuration details as follows:
/// First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set to NULL to fetch pathInfoCount.
/// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch
/// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
/// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
// to number of targetInfoCount(from Second Pass).
/// SUPPORTED OS: Windows 7 and higher
/// </summary>
/// <param name="PathInfoCount"></param>
/// <param name="PathInfo"></param>
/// <returns></returns>
public static NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref UInt32 PathInfoCount, ref NV_DISPLAYCONFIG_PATH_INFO_V2[] PathInfos, bool thirdPass = false)
{
NVAPI_STATUS status;
IntPtr pathInfoBuffer = IntPtr.Zero;
IntPtr currentPathInfoBuffer = IntPtr.Zero;
if (thirdPass)
{
// Copy the supplied object for the third pass (when we have the pathInfoCount and the targetInfoCount for each pathInfo, but we want the details)
// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
//! to number of targetInfoCount(from Second Pass).
NV_DISPLAYCONFIG_PATH_INFO_V2[] passedPathInfo = PathInfos;
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
// Go through the array and create the structure
int overallTargetCount = 0;
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
NVAPI_STATUS status;
IntPtr pathInfoBuffer = IntPtr.Zero;
IntPtr currentPathInfoBuffer = IntPtr.Zero;
if (partFilledIn)
{
// Copy the supplied object for the third pass (when we have the pathInfoCount and the targetInfoCount for each pathInfo, but we want the details)
//NV_DISPLAYCONFIG_PATH_INFO_V1[] passedPathInfo = PathInfos;
//PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V1[PathInfoCount];
// Go through the array and create the structure
int overallTargetCount = 0;
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
// Copy the information passed in, into the buffer we want to pass
//PathInfos[x].Version = MAKE_NVAPI_VERSION(Marshal.SizeOf(passedPathInfo[x]),1);
*//*PathInfos[x].SourceId = passedPathInfo[x].SourceId;
PathInfos[x].TargetInfoCount = passedPathInfo[x].TargetInfoCount;
PathInfos[x].TargetInfo = passedPathInfo[x].TargetInfo;
PathInfos[x].SourceModeInfo = = passedPathInfo[x].SourceModeInfo;*//*
overallTargetCount += (int)PathInfos[x].TargetInfoCount;
}
// Initialize unmanged memory to hold the unmanaged array of structs
int memorySizeRequired = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V1)) * (int)PathInfoCount;
pathInfoBuffer = Marshal.AllocCoTaskMem(memorySizeRequired);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
currentPathInfoBuffer = pathInfoBuffer;
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
// Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, false);
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[x]));
}
// Copy the information passed in, into the buffer we want to pass
}
else
{
// Build a new blank object for the second pass (when we have the pathInfoCount, but want the targetInfoCount for each pathInfo)
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V1[PathInfoCount];
// Initialize unmanged memory to hold the unmanaged array of structs
pathInfoBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V1)) * (int)PathInfoCount);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
currentPathInfoBuffer = pathInfoBuffer;
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
PathInfos[x].Version = MAKE_NVAPI_VERSION(Marshal.SizeOf(PathInfos[x]), 1);
PathInfos[x].SourceModeInfo = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1();
// Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, false);
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[x]));
}
}
if (DISP_GetDisplayConfigInternal != null)
{
// Use the unmanaged buffer in the unmanaged C call
status = DISP_GetDisplayConfigInternal(ref PathInfoCount, pathInfoBuffer);
if (status == NVAPI_STATUS.NVAPI_OK)
{
// If everything worked, then copy the data back from the unmanaged array into the managed array
// So that we can use it in C# land
// Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
currentPathInfoBuffer = pathInfoBuffer;
// Create a managed array to store the received information within
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V1[PathInfoCount];
// Go through the memory buffer item by item and copy the items into the managed array
for (int i = 0; i < PathInfoCount; i++)
{
// build a structure in the array slot
PathInfos[i] = new NV_DISPLAYCONFIG_PATH_INFO_V1();
// fill the array slot structure with the data from the buffer
PathInfos[i] = (NV_DISPLAYCONFIG_PATH_INFO_V1)Marshal.PtrToStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V1));
// destroy the bit of memory we no longer need
Marshal.DestroyStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V1));
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[i]));
}
}
}
else
{
status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
}
Marshal.FreeCoTaskMem(pathInfoBuffer);
return status;
PathInfos[x].SourceId = passedPathInfo[x].SourceId;
PathInfos[x].TargetInfoCount = passedPathInfo[x].TargetInfoCount;
PathInfos[x].TargetInfo = passedPathInfo[x].TargetInfo;
PathInfos[x].SourceModeInfo = passedPathInfo[x].SourceModeInfo;
overallTargetCount += (int)PathInfos[x].TargetInfoCount;
PathInfos[x].Version = MAKE_NVAPI_VERSION(Marshal.SizeOf(passedPathInfo[x]), 1);
}
// Initialize unmanged memory to hold the unmanaged array of structs
int memorySizeRequired = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2)) * (int)PathInfoCount;
pathInfoBuffer = Marshal.AllocCoTaskMem(memorySizeRequired);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
currentPathInfoBuffer = pathInfoBuffer;
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
// Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, false);
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[x]));
}
// NVAPI_INTERFACE NvAPI_DISP_GetDisplayConfig(__inout NvU32 *pathInfoCount, __out_ecount_full_opt(*pathInfoCount) NV_DISPLAYCONFIG_PATH_INFO *pathInfo);
// NvAPIMosaic_EnumDisplayGrids
private delegate NVAPI_STATUS DISP_GetDisplayConfigDelegateNull(
[In][Out] ref UInt32 pathInfoCount,
[In][Out] IntPtr pathInfoBuffer);
private static readonly DISP_GetDisplayConfigDelegateNull DISP_GetDisplayConfigInternalNull;
/// <summary>
/// DESCRIPTION: This API lets caller retrieve the current global display configuration.
/// USAGE: The caller might have to call this three times to fetch all the required configuration details as follows:
/// First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set to NULL to fetch pathInfoCount.
/// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch
/// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
/// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
// to number of targetInfoCount(from Second Pass).
/// SUPPORTED OS: Windows 7 and higher
/// </summary>
/// <param name="PathInfoCount"></param>
/// <returns></returns>
public static NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref UInt32 PathInfoCount)
}
else
{
// This is the second pass
// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch
// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
// Build a new blank object for the second pass (when we have the pathInfoCount, but want the targetInfoCount for each pathInfo)
// Build a managed structure for us to use as a data source for another object that the unmanaged NVAPI C library can use
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
// Prepare the struct for second pass duties
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
NVAPI_STATUS status;
IntPtr pathInfos = IntPtr.Zero;
NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1 sourceMode = new NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1();
IntPtr sourceModeBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_SOURCE_MODE_INFO_V1)));
Marshal.StructureToPtr(sourceMode, sourceModeBuffer, true);
PathInfos[x].Version = NVImport.NV_DISPLAYCONFIG_PATH_INFO_V2_VER;
PathInfos[x].SourceModeInfo = sourceModeBuffer;
/*PathInfos[x].SourceModeInfo.Resolution = new NV_RESOLUTION();
PathInfos[x].SourceModeInfo.Position = new NV_POSITION();
//PathInfos[x].SourceModeInfo = null;
PathInfos[x].TargetInfoCount = 0;
PathInfos[x].TargetInfo = IntPtr.Zero;
//!< This field is reserved. There is ongoing debate if we need this field.
//!< Identifies sourceIds used by Windows. If all sourceIds are 0,
//!< these will be computed automatically.
PathInfos[x].SourceId = 0;
PathInfos[x].Flags = 0;
PathInfos[x].OSAdapterID = new NV_LUID();
//PathInfos[x].OSAdapterID = IntPtr.Zero;*/
}
// Initialize unmanged memory to hold the unmanaged array of structs
int sizeOfOneStruct = Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
int sizeOfAllStructs = sizeOfOneStruct * (int)PathInfoCount;
//int sizeOfOneStruct = Marshal.SizeOf(PathInfos);
pathInfoBuffer = Marshal.AllocCoTaskMem(sizeOfAllStructs);
// Also set another memory pointer to the same place so that we can do the memory copying item by item
// as we have to do it ourselves (there isn't an easy to use Marshal equivalent)
currentPathInfoBuffer = pathInfoBuffer;
// Go through the array and copy things from managed code to unmanaged code
for (Int32 x = 0; x < (Int32)PathInfoCount; x++)
{
// Marshal a single gridtopology into unmanaged code ready for sending to the unmanaged NVAPI function
Marshal.StructureToPtr(PathInfos[x], currentPathInfoBuffer, true);
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer.ToInt64() + Marshal.SizeOf(typeof(NV_DISPLAYCONFIG_PATH_TARGET_INFO_V2)));
}
}
if (DISP_GetDisplayConfigInternalNull != null) { status = DISP_GetDisplayConfigInternalNull(ref PathInfoCount, pathInfos); }
else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
return status;
}*/
if (DISP_GetDisplayConfigInternal != null)
{
// Use the unmanaged buffer in the unmanaged C call
status = DISP_GetDisplayConfigInternal(ref PathInfoCount, pathInfoBuffer);
if (status == NVAPI_STATUS.NVAPI_OK)
{
// If everything worked, then copy the data back from the unmanaged array into the managed array
// So that we can use it in C# land
// Reset the memory pointer we're using for tracking where we are back to the start of the unmanaged memory buffer
currentPathInfoBuffer = pathInfoBuffer;
// Create a managed array to store the received information within
PathInfos = new NV_DISPLAYCONFIG_PATH_INFO_V2[PathInfoCount];
// Go through the memory buffer item by item and copy the items into the managed array
for (int i = 0; i < PathInfoCount; i++)
{
// build a structure in the array slot
PathInfos[i] = new NV_DISPLAYCONFIG_PATH_INFO_V2();
// fill the array slot structure with the data from the buffer
PathInfos[i] = (NV_DISPLAYCONFIG_PATH_INFO_V2)Marshal.PtrToStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
// destroy the bit of memory we no longer need
Marshal.DestroyStructure(currentPathInfoBuffer, typeof(NV_DISPLAYCONFIG_PATH_INFO_V2));
// advance the buffer forwards to the next object
currentPathInfoBuffer = (IntPtr)((long)currentPathInfoBuffer + Marshal.SizeOf(PathInfos[i]));
}
}
}
else
{
status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND;
}
Marshal.FreeCoTaskMem(pathInfoBuffer);
return status;
}
// NVAPI_INTERFACE NvAPI_DISP_GetDisplayConfig(__inout NvU32 *pathInfoCount, __out_ecount_full_opt(*pathInfoCount) NV_DISPLAYCONFIG_PATH_INFO *pathInfo);
// NvAPIMosaic_EnumDisplayGrids
private delegate NVAPI_STATUS DISP_GetDisplayConfigDelegateNull(
[In][Out] ref UInt32 pathInfoCount,
[In][Out] IntPtr pathInfoBuffer);
private static readonly DISP_GetDisplayConfigDelegateNull DISP_GetDisplayConfigInternalNull;
/// <summary>
/// DESCRIPTION: This API lets caller retrieve the current global display configuration.
/// USAGE: The caller might have to call this three times to fetch all the required configuration details as follows:
/// First Pass: Caller should Call NvAPI_DISP_GetDisplayConfig() with pathInfo set to NULL to fetch pathInfoCount.
/// Second Pass: Allocate memory for pathInfo with respect to the number of pathInfoCount(from First Pass) to fetch
/// targetInfoCount. If sourceModeInfo is needed allocate memory or it can be initialized to NULL.
/// Third Pass(Optional, only required if target information is required): Allocate memory for targetInfo with respect
// to number of targetInfoCount(from Second Pass).
/// SUPPORTED OS: Windows 7 and higher
/// </summary>
/// <param name="PathInfoCount"></param>
/// <returns></returns>
public static NVAPI_STATUS NvAPI_DISP_GetDisplayConfig(ref UInt32 PathInfoCount)
{
NVAPI_STATUS status;
IntPtr pathInfos = IntPtr.Zero;
if (DISP_GetDisplayConfigInternalNull != null) { status = DISP_GetDisplayConfigInternalNull(ref PathInfoCount, pathInfos); }
else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
return status;
}
// NVAPI_INTERFACE NvAPI_DISP_GetDisplayIdByDisplayName(const char *displayName, NvU32* displayId);
@ -4173,6 +4306,28 @@ namespace DisplayMagicianShared.NVIDIA
return status;
}
//NVAPI_INTERFACE NvAPI_DISP_EnumCustomDisplay(__in NvU32 displayId, __inout NV_HDR_CAPABILITIES *pHdrCapabilities);
private delegate NVAPI_STATUS Disp_EnumCustomDisplayDelegate(
[In] UInt32 displayId,
[In] UInt32 index,
[In][Out] ref NV_CUSTOM_DISPLAY_V1 pCustDisp);
private static readonly Disp_EnumCustomDisplayDelegate Disp_EnumCustomDisplayInternal;
/// <summary>
//! This API gets High Dynamic Range (HDR) capabilities of the display.
/// <param name="displayId"></param>
/// <param name="pHdrCapabilities"></param>
/// <returns></returns>
public static NVAPI_STATUS NvAPI_DISP_EnumCustomDisplay(UInt32 displayId, UInt32 index, ref NV_CUSTOM_DISPLAY_V1 pCustDisp)
{
NVAPI_STATUS status;
pCustDisp.Version = NVImport.NV_CUSTOM_DISPLAY_V1_VER;
pCustDisp.SourcePartition = new NV_VIEWPORTF(0, 0, 1, 1);
if (Disp_EnumCustomDisplayInternal != null) { status = Disp_EnumCustomDisplayInternal(displayId, index, ref pCustDisp); }
else { status = NVAPI_STATUS.NVAPI_FUNCTION_NOT_FOUND; }
return status;
}
//NVAPI_INTERFACE NvAPI_GPU_GetFullName(NvPhysicalGpuHandle hPhysicalGpu, NvAPI_ShortString szName);
private delegate NVAPI_STATUS GPU_GetFullNameDelegate(
[In] PhysicalGpuHandle gpuHandle,

File diff suppressed because it is too large Load Diff

View File

@ -1017,33 +1017,84 @@ namespace DisplayMagicianShared.Windows
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Patching the adapter IDs to make the saved config valid");
PatchAdapterIDs(ref displayConfig, allWindowsDisplayConfig.DisplayAdapters);
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Testing whether the display configuration is valid");
// Test whether a specified display configuration is supported on the computer
uint myPathsCount = (uint)displayConfig.DisplayConfigPaths.Length;
uint myModesCount = (uint)displayConfig.DisplayConfigModes.Length;
/*SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Testing whether the display configuration is valid");
// Test whether a specified display configuration is supported on the computer
// Note: THe flags are different as we cannot use SDC_FORCE_MODE_ENUMERATION unless we're actually applying the config
WIN32STATUS err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_VALIDATE);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Successfully validated that the display configuration supplied would work!");
}
else
else if (err == WIN32STATUS.ERROR_INVALID_PARAMETER)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't validate the display configuration supplied. This display configuration won't work if applied.");
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The combination of parameters and flags specified is invalid. This display configuration won't work if applied.");
return false;
}
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Yay! The display configuration is valid! Attempting to set the Display Config now");
else if (err == WIN32STATUS.ERROR_NOT_SUPPORTED)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function is only supported on a system with a WDDM driver running. This display configuration won't work if applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_ACCESS_DENIED)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The caller does not have access to the console session. This error occurs if the calling process does not have access to the current desktop or is running on a remote session. This display configuration won't work if applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_GEN_FAILURE)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: An unspecified error occurred. This display configuration won't work if applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_BAD_CONFIGURATION)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The function could not find a workable solution for the source and target modes that the caller did not specify. This display configuration won't work if applied.");
return false;
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: SetDisplayConfig couldn't validate the display configuration supplied. This display configuration won't work if applied.");
return false;
}
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Yay! The display configuration is valid! Attempting to set the Display Config now");*/
// Now set the specified display configuration for this computer
err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_SET | SDC.SDC_FORCE_MODE_ENUMERATION);
WIN32STATUS err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_SET | SDC.SDC_FORCE_MODE_ENUMERATION);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Successfully set the display configuration to the settings supplied!");
}
else if (err == WIN32STATUS.ERROR_INVALID_PARAMETER)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The combination of parameters and flags specified is invalid. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_NOT_SUPPORTED)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The system is not running a graphics driver that was written according to the Windows Display Driver Model (WDDM). The function is only supported on a system with a WDDM driver running. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_ACCESS_DENIED)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The caller does not have access to the console session. This error occurs if the calling process does not have access to the current desktop or is running on a remote session. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_GEN_FAILURE)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: An unspecified error occurred. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_BAD_CONFIGURATION)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: The function could not find a workable solution for the source and target modes that the caller did not specify. Display configuration not applied.");
return false;
}
else
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: ERROR - SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong.");
throw new WinLibraryException($"SetDisplayConfig couldn't set the display configuration using the settings supplied. Something is wrong.");
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: SetDisplayConfig couldn't set the display configuration using the settings supplied. Display configuration not applied.");
return false;
}
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: SUCCESS! The display configuration has been successfully applied");
@ -1445,7 +1496,7 @@ namespace DisplayMagicianShared.Windows
if (!displayIdentifiers.Contains(displayIdentifier))
{
displayIdentifiers.Add(displayIdentifier);
SharedLogger.logger.Debug($"WinLibrary/GetSomeDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: DisplayIdentifier: {displayIdentifier}");
}
}