Updated NVIDIA Library and WinLibrary based on testing

Did a HUGE amount of testing with the amazing help of @domenic as part of #41, and we finally got the right configuration sorted out! This update is a reflection of the changes required.
This commit is contained in:
Terry MacDonald 2021-11-19 22:20:43 +13:00
parent db0bfbecbe
commit 77ab0f20f1
4 changed files with 295 additions and 60 deletions

View File

@ -1293,7 +1293,7 @@ namespace DisplayMagicianShared.NVIDIA
NVAPI_STATUS NVStatus = NVAPI_STATUS.NVAPI_ERROR;
// Remove any custom NVIDIA Colour settings
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off colour if it's default set colour.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off colour if it's default set colour.");
// Now we try to set each display color
foreach (var colorDataDict in displayConfig.ColorConfig.ColorData)
{
@ -1305,91 +1305,91 @@ namespace DisplayMagicianShared.NVIDIA
if (!ActiveDisplayConfig.ColorConfig.ColorData.ContainsKey(displayId))
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Display {displayId} doesn't exist in this setup, so skipping turning off prior NVIDIA Color Settings.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping turning off prior NVIDIA Color Settings.");
continue;
}
// If the setting for this display is not the same as we want, then we set it to NV_COLOR_SELECTION_POLICY_BEST_QUALITY
if (ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy != colorData.ColorSelectionPolicy)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off NVIDIA customer colour settings for display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off NVIDIA customer colour settings for display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
// Force the colorData to be NV_COLOR_SELECTION_POLICY_BEST_QUALITY so that we return the color control to Windows
// We will change the colorData to whatever is required later on
colorData = displayConfig.ColorConfig.ColorData[displayId];
colorData.ColorSelectionPolicy = NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY;
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} and they are {ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off standard colour mode for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want the standard colour settings to be {displayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} and they are {ActiveDisplayConfig.ColorConfig.ColorData[displayId].ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off standard colour mode for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings Color selection policy {colorData.ColorSelectionPolicy.ToString("G")} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings BPC {colorData.Bpc} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour format {colorData.ColorFormat} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colourimetry {colorData.Colorimetry} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings colour depth {colorData.Depth} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want standard colour settings dynamic range {colorData.DynamicRange} for Mosaic display {displayId}");
// Set the command as a 'SET'
colorData.Cmd = NV_COLOR_CMD.NV_COLOR_CMD_SET;
NVStatus = NVImport.NvAPI_Disp_ColorControl(displayIdAsUInt32, ref colorData);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_ColorControl returned OK. BPC is set to {colorData.Bpc.ToString("G")}. Color Format is set to {colorData.ColorFormat.ToString("G")}. Colorimetry is set to {colorData.Colorimetry.ToString("G")}. Color Selection Policy is set to {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth is set to {colorData.Depth.ToString("G")}. Dynamic Range is set to {colorData.DynamicRange.ToString("G")}");
switch (colorData.ColorSelectionPolicy)
{
case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_USER:
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_USER so the color settings have been set by the user in the NVIDIA Control Panel.");
break;
case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_BEST_QUALITY: // Also matches NV_COLOR_SELECTION_POLICY_DEFAULT as it is 1
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_BEST_QUALITY so the color settings are being handled by the Windows OS.");
break;
case NV_COLOR_SELECTION_POLICY.NV_COLOR_SELECTION_POLICY_UNKNOWN:
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Color Selection Policy is set to NV_COLOR_SELECTION_POLICY_UNKNOWN so the color settings aren't being handled by either the Windows OS or the NVIDIA Setup!");
break;
}
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: Your monitor {displayId} doesn't support the requested color settings. BPC = {colorData.Bpc.ToString("G")}. Color Format = {colorData.ColorFormat.ToString("G")}. Colorimetry = {colorData.Colorimetry.ToString("G")}. Color Selection Policy = {colorData.ColorSelectionPolicy.ToString("G")}. Color Depth = {colorData.Depth.ToString("G")}. Dynamic Range = {colorData.DynamicRange.ToString("G")}. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input buffer is not large enough to hold it's contents. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INVALID_DISPLAY_ID)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_API_NOT_INITIALIZED)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: The NvAPI API needs to be initialized first. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NO_IMPLEMENTATION)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: This entry point not available in this NVIDIA Driver. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_ERROR)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_ColorControl() returned error code {NVStatus}");
}
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Some non standard error occurred while seting the color settings! NvAPI_Disp_ColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support this color mode.");
}
}
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn off custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA colour settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA colour mode.");
}
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning off prior NVIDIA specific colour settings for display {displayId}.");
SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA specific colour settings for display {displayId}.");
}
}
// Remove any custom NVIDIA HDR Colour settings
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn off HDR colour if it's user set HDR colour.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn off HDR colour if it's user set HDR colour.");
// Now we try to set each display color
foreach (var hdrColorDataDict in displayConfig.HdrConfig.HdrColorData)
{
@ -1403,64 +1403,64 @@ namespace DisplayMagicianShared.NVIDIA
if (!ActiveDisplayConfig.HdrConfig.HdrColorData.ContainsKey(displayId))
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Display {displayId} doesn't exist in this setup, so skipping turning off HDR.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Display {displayId} doesn't exist in this setup, so skipping turning off HDR.");
continue;
}
// if it's not the same HDR we want, then we turn off HDR (and will apply it if needed later on in SetActiveOverride)
if (ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode != hdrColorData.HdrMode)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want to turn on custom HDR mode for display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want to turn on custom HDR mode for display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: HDR mode is currently {ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode.ToString("G")} for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: HDR mode is currently {ActiveDisplayConfig.HdrConfig.HdrColorData[displayId].HdrMode.ToString("G")} for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings BPC {hdrColorData.HdrBpc} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Colour Format {hdrColorData.HdrColorFormat} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR dynamic range {hdrColorData.HdrDynamicRange} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings HDR Mode {hdrColorData.HdrMode} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Mastering Display Data {hdrColorData.MasteringDisplayData} for Mosaic display {displayId}");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want HDR settings Static Meradata Description ID {hdrColorData.StaticMetadataDescriptorId} for Mosaic display {displayId}");
// Apply the HDR removal
hdrColorData.Cmd = NV_HDR_CMD.CMD_SET;
hdrColorData.HdrMode = NV_HDR_MODE.OFF;
NVStatus = NVImport.NvAPI_Disp_HdrColorControl(displayIdAsUInt32, ref hdrColorData);
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Disp_HdrColorControl returned OK. We just successfully turned off the HDR mode for Mosaic display {displayId}.");
}
else if (NVStatus == NVAPI_STATUS.NVAPI_INSUFFICIENT_BUFFER)
{
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfigOverride: The input buffer is not large enough to hold it's contents. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
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/SetActiveConfigOverride: The input monitor is either not connected or is not a DP or HDMI panel. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
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/SetActiveConfigOverride: The NvAPI API needs to be initialized first. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
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/SetActiveConfigOverride: This entry point not available in this NVIDIA Driver. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
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/SetActiveConfigOverride: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
SharedLogger.logger.Warn($"NVIDIALibrary/SetActiveConfig: A miscellaneous error occurred. NvAPI_Disp_HdrColorControl() returned error code {NVStatus}");
}
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: Some non standard error occurred while getting Mosaic Topology! NvAPI_Disp_HdrColorControl() returned error code {NVStatus}. It's most likely that your monitor {displayId} doesn't support HDR.");
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 {displayId} doesn't support HDR.");
}
}
else
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfigOverride: We want only want to turn off custom NVIDIA HDR settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA HDR mode.");
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: We want only want to turn off custom NVIDIA HDR settings if needed for display {displayId}, and that currently isn't required. Skipping changing NVIDIA HDR mode.");
}
}
catch (Exception ex)
{
SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfigOverride: Exception caused while turning off prior NVIDIA HDR colour settings for display {displayId}.");
SharedLogger.logger.Error(ex, $"NVIDIALibrary/SetActiveConfig: Exception caused while turning off prior NVIDIA HDR colour settings for display {displayId}.");
}
}
@ -1486,7 +1486,8 @@ namespace DisplayMagicianShared.NVIDIA
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_SetDisplayGrids returned OK.");
//Task.Delay(500);
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Waiting 0.5 second to let the Mosaic display change take place before continuing");
System.Threading.Thread.Sleep(500);
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NO_ACTIVE_SLI_TOPOLOGY)
{
@ -1541,7 +1542,8 @@ namespace DisplayMagicianShared.NVIDIA
if (NVStatus == NVAPI_STATUS.NVAPI_OK)
{
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: NvAPI_Mosaic_EnableCurrentTopo returned OK. Previously set Mosiac config re-enabled.");
//Task.Delay(500);
SharedLogger.logger.Trace($"NVIDIALibrary/SetActiveConfig: Waiting 0.5 second to let the Mosaic display change take place before continuing");
System.Threading.Thread.Sleep(500);
}
else if (NVStatus == NVAPI_STATUS.NVAPI_NOT_SUPPORTED)
{

View File

@ -164,6 +164,7 @@ namespace DisplayMagicianShared.Windows
SDC_FORCE_MODE_ENUMERATION = 0x00001000,
SDC_ALLOW_PATH_ORDER_CHANGES = 0x00002000,
SDC_VIRTUAL_MODE_AWARE = 0x00008000,
SDC_VIRTUAL_REFRESH_RATE_AWARE = 0x00020000,
// Special common combinations (only set in this library)
TEST_IF_VALID_DISPLAYCONFIG = (SDC_VALIDATE | SDC_USE_SUPPLIED_DISPLAY_CONFIG),
@ -971,6 +972,19 @@ namespace DisplayMagicianShared.Windows
public int Right;
public int Bottom;
public RECTL(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
public static RECTL FromXYWH(int x, int y, int width, int height)
{
return new RECTL(x, y, x + width, y + height);
}
public override bool Equals(object obj) => obj is RECTL other && this.Equals(other);
public bool Equals(RECTL other)
=> Left == other.Left &&

View File

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
@ -56,6 +53,8 @@ namespace DisplayMagicianShared.Windows
BadDualView = -6
}
[Flags]
public enum CHANGE_DISPLAY_SETTINGS_FLAGS : UInt32
{
@ -269,6 +268,17 @@ namespace DisplayMagicianShared.Windows
Primary = 1
}
[StructLayout(LayoutKind.Sequential)]
public struct APP_BAR_DATA
{
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public ABE_EDGE uEdge;
public RECTL rc;
public ABS_SETTING lParam;
}
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx
@ -401,6 +411,7 @@ namespace DisplayMagicianShared.Windows
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAY_DEVICE : IEquatable<DISPLAY_DEVICE>
{
[MarshalAs(UnmanagedType.U4)]
public UInt32 Size;
@ -579,8 +590,44 @@ namespace DisplayMagicianShared.Windows
}
}
public enum ABM_MESSAGE : UInt32
{
ABM_NEW = 0x00000000, // Registers a new appbar and specifies the message identifier that the system should use to send notification messages to the appbar.
ABM_REMOVE = 0x00000001, // Unregisters an appbar, removing the bar from the system's internal list.
ABM_QUERYPOS = 0x00000002, // Requests a size and screen position for an appbar.
ABM_SETPOS = 0x00000003, // Sets the size and screen position of an appbar.
ABM_GETSTATE = 0x00000004, // Retrieves the autohide and always-on-top states of the Windows taskbar.
ABM_GETTASKBARPOS = 0x00000005, // Retrieves the bounding rectangle of the Windows taskbar. Note that this applies only to the system taskbar. Other objects, particularly toolbars supplied with third-party software, also can be present. As a result, some of the screen area not covered by the Windows taskbar might not be visible to the user. To retrieve the area of the screen not covered by both the taskbar and other app bars—the working area available to your application—, use the GetMonitorInfo function.
ABM_ACTIVATE = 0x00000006, // Notifies the system to activate or deactivate an appbar. The lParam member of the APPBARDATA pointed to by pData is set to TRUE to activate or FALSE to deactivate.
ABM_GETAUTOHIDEBAR = 0x00000007, // Retrieves the handle to the autohide appbar associated with a particular edge of the screen.
ABM_SETAUTOHIDEBAR = 0x00000008, // Registers or unregisters an autohide appbar for an edge of the screen.
ABM_WINDOWPOSCHANGED = 0x00000009, // Notifies the system when an appbar's position has changed.
ABM_SETSTATE = 0x0000000A, // Windows XP and later: Sets the state of the appbar's autohide and always-on-top attributes.
ABM_GETAUTOHIDEBAREX = 0x0000000B, // Windows XP and later: Retrieves the handle to the autohide appbar associated with a particular edge of a particular monitor.
ABM_SETAUTOHIDEBAREX = 0x0000000C, // Windows XP and later: Registers or unregisters an autohide appbar for an edge of a particular monitor.
}
public enum ABE_EDGE : UInt32
{
ABE_LEFT = 0,
ABE_TOP = 1,
ABE_RIGHT = 2,
ABE_BOTTOM = 3,
}
[Flags]
public enum ABS_SETTING : UInt32
{
ABS_AUTOHIDE = 0x1,
ABS_ALWAYSONTOP = 0x2,
}
class GDIImport
{
private const int ABS_NO_AUTOHIDE = 0x00;
private const int ABS_AUTOHIDE = 0x01;
[DllImport("user32", CharSet = CharSet.Ansi)]
public static extern CHANGE_DISPLAY_RESULTS ChangeDisplaySettingsEx(
string deviceName,
@ -668,6 +715,14 @@ namespace DisplayMagicianShared.Windows
[DllImport("gdi32")]
internal static extern bool SetDeviceGammaRamp(DCHandle dcHandle, ref GAMMA_RAMP ramp);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int cx, int cy, bool repaint);
// This code was part of development to add recording taskbar location and state so that we could apply it later
// Windows 11 doesn't support moving
[DllImport("Shell32.dll", CharSet = CharSet.Auto)]
private static extern int SHAppBarMessage(ABM_MESSAGE dwMessage, ref APP_BAR_DATA abd);
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
internal delegate int MonitorEnumProcedure(
IntPtr monitorHandle,
@ -675,5 +730,94 @@ namespace DisplayMagicianShared.Windows
ref RECTL rect,
IntPtr callbackObject
);
public static APP_BAR_DATA GetTaskbarPosition()
{
APP_BAR_DATA abd = new APP_BAR_DATA();
abd.cbSize = Marshal.SizeOf(abd);
// Query the system for an approved size and position.
SHAppBarMessage(ABM_MESSAGE.ABM_GETTASKBARPOS, ref abd);
return abd;
}
public static bool GetTaskbarAutoHide(APP_BAR_DATA abd)
{
// Query the system for an approved size and position.
ABS_SETTING state = (ABS_SETTING)SHAppBarMessage(ABM_MESSAGE.ABM_GETSTATE, ref abd);
return state.HasFlag(ABS_SETTING.ABS_AUTOHIDE);
}
//public static void MoveTaskbar(APP_BAR_DATA abd, ABE_EDGE edge, Size idealSize)
public static void SetTaskbarPosition(APP_BAR_DATA abd, ABE_EDGE edge)
{
abd.uEdge = edge;
SHAppBarMessage(ABM_MESSAGE.ABM_SETPOS, ref abd);
/*// Get current size
int idealSize = 100;
if (edge == ABE_EDGE.ABE_LEFT || edge == ABE_EDGE.ABE_RIGHT)
{
abd.rc.Top = 0;
abd.rc.Bottom = SystemInformation.PrimaryMonitorSize.Height;
if (edge == ABE_EDGE.ABE_LEFT)
{
abd.rc.Right = idealSize;
}
else
{
abd.rc.Right = SystemInformation.PrimaryMonitorSize.Width;
abd.rc.Left = abd.rc.Right - idealSize;
}
}
else
{
abd.rc.Left = 0;
abd.rc.Right = SystemInformation.PrimaryMonitorSize.Width;
if (edge == ABE_EDGE.ABE_TOP)
{
abd.rc.Bottom = idealSize;
}
else
{
abd.rc.Bottom = SystemInformation.PrimaryMonitorSize.Height;
abd.rc.Top = abd.rc.Bottom - idealSize;
}
}
ABS_SETTING state = (ABS_SETTING)SHAppBarMessage(ABM_MESSAGE.ABM_GETSTATE, ref abd);*/
}
// THE FOLLOWING CODE WAS AN ATTEMPT TO SET THE TASKBAR POSITION USING CODE
// TURNS OUT WE CAN'T ACTUALLY SET THE POSITION PROGRAMMATICALLY iIN WIN10 or WIN11
// Next we want to remember where the windows toolbar is for each screen
// Query the system for an approved size and position.
// APP_BAR_DATA taskbarPosition = GDIImport.GetTaskbarPosition();
// bool taskbarAutoHide = GDIImport.GetTaskbarAutoHide(taskbarPosition);
// try to move the taskbar
// GDIImport.SetTaskbarPosition(taskbarPosition, ABE_EDGE.ABE_TOP);
// GDIImport.SetTaskbarAutoHide(taskbarPosition, true);
public static void SetTaskbarAutoHide(APP_BAR_DATA abd, bool hide)
{
if (hide)
{
// Set the autohide flag
abd.lParam |= ABS_SETTING.ABS_AUTOHIDE;
}
else
{
// Clear the autohide flag
abd.lParam &= ~ABS_SETTING.ABS_AUTOHIDE;
}
SHAppBarMessage(ABM_MESSAGE.ABM_GETSTATE, ref abd);
}
}
}

View File

@ -999,11 +999,11 @@ namespace DisplayMagicianShared.Windows
if (displayConfig.IsCloned)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: We have a cloned display in this display profile, so using the Windows GDI to set the layout");
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: We have a cloned display in this display profile");
}
else
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: We have no cloned displays in thus display profile, so using the Windows CCD to set the layout");
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: We have no cloned displays in thus display profile");
}
// Now we go through the Paths to update the LUIDs as per Soroush's suggestion
@ -1021,27 +1021,97 @@ namespace DisplayMagicianShared.Windows
}
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;
SharedLogger.logger.Warn($"WinLibrary/SetActiveConfig: The combination of parameters and flags specified is invalid. Display configuration not applied. So trying again without SDC_FORCE_MODE_ENUMERATION as that works on some computers.");
// Try it again, because in some systems it doesn't work at the first try
err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.DISPLAYMAGICIAN_SET);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Retry. Successfully set the display configuration to the settings supplied!");
}
else if (err == WIN32STATUS.ERROR_INVALID_PARAMETER)
{
SharedLogger.logger.Warn($"WinLibrary/SetActiveConfig: Retry. The combination of parameters and flags specified is invalid. Display configuration not applied. So trying again without any specific data other than the topology as that works on some computers.");
// Try it again, because in some systems it doesn't work at the 2nd try! This is a fallback mode just to get something on the screen!
err = CCDImport.SetDisplayConfig(myPathsCount, displayConfig.DisplayConfigPaths, myModesCount, displayConfig.DisplayConfigModes, SDC.SDC_APPLY | SDC.SDC_TOPOLOGY_SUPPLIED | SDC.SDC_ALLOW_CHANGES | SDC.SDC_ALLOW_PATH_ORDER_CHANGES);
if (err == WIN32STATUS.ERROR_SUCCESS)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Retry 2. Successfully set the display configuration to the settings supplied!");
}
else if (err == WIN32STATUS.ERROR_INVALID_PARAMETER)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Retry 2. The combination of parameters and flags specified is invalid. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_NOT_SUPPORTED)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Retry 2. 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.Error($"WinLibrary/SetActiveConfig: Retry 2. 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.Error($"WinLibrary/SetActiveConfig: Retry 2. An unspecified error occurred. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_BAD_CONFIGURATION)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Retry 2. 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: Retry 2. SetDisplayConfig couldn't set the display configuration using the settings supplied. Display configuration not applied.");
return false;
}
}
else if (err == WIN32STATUS.ERROR_NOT_SUPPORTED)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Retry. 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.Error($"WinLibrary/SetActiveConfig: Retry. 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.Error($"WinLibrary/SetActiveConfig: Retry. An unspecified error occurred. Display configuration not applied.");
return false;
}
else if (err == WIN32STATUS.ERROR_BAD_CONFIGURATION)
{
SharedLogger.logger.Error($"WinLibrary/SetActiveConfig: Retry. 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: Retry. SetDisplayConfig couldn't set the display configuration using the settings supplied. 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.");
SharedLogger.logger.Error($"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.");
SharedLogger.logger.Error($"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.");
SharedLogger.logger.Error($"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.");
SharedLogger.logger.Error($"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
@ -1055,6 +1125,8 @@ namespace DisplayMagicianShared.Windows
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Waiting 0.5 seconds to let the display change take place before adjusting the Windows CCD HDR settings");
System.Threading.Thread.Sleep(500);
// NOTE: There is currently no way within Windows CCD API to set the HDR settings to any particular setting
// This code will only turn on the HDR setting.
foreach (ADVANCED_HDR_INFO_PER_PATH myHDRstate in displayConfig.DisplayHDRStates)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Trying to get information whether HDR color is in use now on Display {myHDRstate.Id}.");
@ -1069,9 +1141,10 @@ namespace DisplayMagicianShared.Windows
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: Advanced Color Info gathered from Display {myHDRstate.Id}");
if (myHDRstate.AdvancedColorInfo.AdvancedColorSupported && colorInfo.AdvancedColorEnabled != myHDRstate.AdvancedColorInfo.AdvancedColorEnabled)
if (myHDRstate.AdvancedColorInfo.AdvancedColorEnabled != colorInfo.AdvancedColorEnabled)
{
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: HDR is available for use on Display {myHDRstate.Id}, and we want it set to {myHDRstate.AdvancedColorInfo.AdvancedColorEnabled} but is currently {colorInfo.AdvancedColorEnabled}.");
SharedLogger.logger.Trace($"WinLibrary/SetActiveConfig: HDR is available for use on Display {myHDRstate.Id}, and we want it set to {myHDRstate.AdvancedColorInfo.BitsPerColorChannel} but is currently {colorInfo.AdvancedColorEnabled}.");
var setColorState = new DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE();
setColorState.Header.Type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE;
@ -1102,7 +1175,8 @@ namespace DisplayMagicianShared.Windows
}
// Get the existing displays
// Get the existing displays config
Dictionary<string, GDI_DISPLAY_SETTING> currentGdiDisplaySettings = GetGdiDisplaySettings();
// Apply the previously saved display settings to the new displays (match them up)
@ -1177,6 +1251,7 @@ namespace DisplayMagicianShared.Windows
}
}
return true;
}