Added initial CCD library code

Added some basic CCD library functionality
to be able to set Windows displays directly
from the code. This will enable future native
HDR support through windows, as well as
allow positioning and screen setup to work
better through here than via the AMD driver.

Will still need to work on AMD Eyefinity support
once this is completed.
This commit is contained in:
Terry MacDonald 2021-06-29 22:15:57 +12:00
parent 600bb39ec6
commit 86375b06aa
15 changed files with 750 additions and 27 deletions

View File

@ -60,8 +60,11 @@ namespace DisplayMagician.UIForms
this.lbl_hotkey_assigned = new System.Windows.Forms.Label();
this.dv_profile = new DisplayMagicianShared.UserControls.DisplayView();
this.panel1 = new System.Windows.Forms.Panel();
this.pbLogo = new System.Windows.Forms.PictureBox();
this.menu_profiles.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pb_down_arrow)).BeginInit();
this.panel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pbLogo)).BeginInit();
this.SuspendLayout();
//
// btn_apply
@ -364,11 +367,22 @@ namespace DisplayMagician.UIForms
// panel1
//
this.panel1.BackColor = System.Drawing.Color.DimGray;
this.panel1.Controls.Add(this.pbLogo);
this.panel1.Location = new System.Drawing.Point(0, 61);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(976, 521);
this.panel1.TabIndex = 37;
//
// pbLogo
//
this.pbLogo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.pbLogo.Location = new System.Drawing.Point(854, 14);
this.pbLogo.Name = "pbLogo";
this.pbLogo.Size = new System.Drawing.Size(100, 49);
this.pbLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.pbLogo.TabIndex = 0;
this.pbLogo.TabStop = false;
//
// DisplayProfileForm
//
this.AcceptButton = this.btn_apply;
@ -407,6 +421,8 @@ namespace DisplayMagician.UIForms
this.Load += new System.EventHandler(this.DisplayProfileForm_Load);
this.menu_profiles.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pb_down_arrow)).EndInit();
this.panel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.pbLogo)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
@ -440,6 +456,7 @@ namespace DisplayMagician.UIForms
private System.Windows.Forms.Button btn_hotkey;
private System.Windows.Forms.Label lbl_hotkey_assigned;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.PictureBox pbLogo;
}
}

View File

@ -259,6 +259,12 @@ namespace DisplayMagician.UIForms
// We also need to load the saved profile name to show the user
lbl_profile_shown.Text = _selectedProfile.Name;
// And show the logo for the driver
if (_selectedProfile.Driver == "AMD")
{
pbLogo.Image = PickBitmapBasedOnBgColour(BackColor, Properties.Resources.amdblack, Properties.Resources.amdwhite);
}
// And update the save/rename textbox
txt_profile_save_name.Text = _selectedProfile.Name;
@ -467,6 +473,18 @@ namespace DisplayMagician.UIForms
}
}
private Bitmap PickBitmapBasedOnBgColour(Color bgColour, Bitmap lightBitmap, Bitmap darkBitmap)
{
if ((bgColour.R * 0.299 + bgColour.G * 0.587 + bgColour.B * 0.114) > 186)
{
return darkBitmap;
}
else
{
return lightBitmap;
}
}
private void btn_hotkey_Click(object sender, EventArgs e)
{
Keys testHotkey;

View File

@ -1181,7 +1181,6 @@ namespace DisplayMagicianShared.AMD
displayToCreate.HDRSupported = false;
displayToCreate.HDREnabled = false;
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: ### Display Info for Display #{oneDisplayInfo.DisplayID.DisplayLogicalIndex} on Adapter #{oneAdapter.AdapterIndex} ###");
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: Display Connector = {displayConnector.ToString("G")}");
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: Display Controller Index = {oneDisplayInfo.DisplayControllerIndex}");
@ -1252,6 +1251,9 @@ namespace DisplayMagicianShared.AMD
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: DisplayMode X Resolution = {oneDisplayMode.XRes}");
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: DisplayMode Y Position = {oneDisplayMode.YPos}");
SharedLogger.logger.Trace($"AMDLibrary/GetActiveprofile: DisplayMode Y Resolution = {oneDisplayMode.YRes}");
}
}
else
@ -1576,6 +1578,14 @@ namespace DisplayMagicianShared.AMD
// Set the display mode timing override configuration
//ADL.ADL2_Display_ModeTimingOverride_Set
// Validate the display map config we want to set
//ADL.ADL2_Display_DisplayMapConfig_Validate
// Figure out which display targets need to be added or removed in the display map config
//ADL.ADL2_Display_DisplayMapConfig_PossibleAddAndRemove
// Set the display map config
//ADL.ADL2_Display_DisplayMapConfig_Set
// Set the HDR function if needed
if (storedAMDDisplay.HDREnabled)

View File

@ -343,6 +343,12 @@ namespace DisplayMagicianShared.AMD
screen.ScreenWidth = mode.XRes;
screen.ScreenHeight = mode.YRes;
// If we're at the 0,0 coordinate then we're the primary monitor
if (screen.ScreenX == 0 && screen.ScreenY == 0)
{
screen.IsPrimary = true;
}
// HDR information
if (display.HDRSupported)
{
@ -589,33 +595,91 @@ namespace DisplayMagicianShared.AMD
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
int foundPathsCount = 0;
int foundOtherPathsCount = 0;
int foundDisplayCount = 0;
int foundOtherDisplayCount = 0;
// TODO: Fix this so it finds compares ProfileData
/*foreach (Topology.Path profilePath in x.Paths)
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
if (y.Paths.Contains(profilePath))
foreach (AMDDisplay xdisplay in xadapter.Displays)
{
foundPathsCount++;
foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
if (ydisplay.Equals(xdisplay))
{
foreach (var ydisplaymode in ydisplay.DisplayModes)
{
foreach (var xdisplaymode in xdisplay.DisplayModes)
{
if (ydisplaymode.Equals(xdisplaymode))
{
foundDisplayCount++;
continue;
}
}
}
}
foreach (Topology.Path otherPath in y.Paths)
}
}
}
}
foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
if (x.Paths.Contains(otherPath))
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
foundOtherPathsCount++;
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
foreach (AMDDisplay xdisplay in xadapter.Displays)
{
if (xdisplay.Equals(ydisplay))
{
foreach (var xdisplaymode in xdisplay.DisplayModes)
{
foreach (var ydisplaymode in ydisplay.DisplayModes)
{
if (xdisplaymode.Equals(ydisplaymode))
{
foundOtherDisplayCount++;
continue;
}
}
}
}
}
}
}
}
/*foreach (AMDAdapter yadapter in y.ProfileData.Adapters)
{
foreach (AMDDisplay ydisplay in yadapter.Displays)
{
foreach (AMDAdapter xadapter in x.ProfileData.Adapters)
{
if (xadapter.Displays.Contains(ydisplay))
{
foundOtherDisplayCount++;
continue;
}
}
}
}*/
if (foundPathsCount == foundOtherPathsCount)
return true;
else
// If this matches then there are an additional screen or not enough screens
if (foundDisplayCount != foundOtherDisplayCount)
return false;
// Now we need to check the location of the screens
if (!x.ProfileData.Equals(y.ProfileData))
return false;
return true;
}
// If Equals() returns true for a pair of objects

View File

@ -90,6 +90,8 @@
<Compile Include="UserControls\DisplayView.Designer.cs">
<DependentUpon>DisplayView.cs</DependentUpon>
</Compile>
<Compile Include="Windows\CCD.cs" />
<Compile Include="Windows\WindowsLibrary.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
@ -156,8 +158,18 @@
<EmbedInteropTypes>True</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Windows\" />
<None Include="Properties\amdblack.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\amdwhite.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\nvidiablack.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\nvidiawhite.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -478,6 +478,13 @@ namespace DisplayMagicianShared
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
if (screen.IsPrimary)
{
//screenBgColour = Color.FromArgb(255, 66, 173, 245);
screenBgColour = Color.FromArgb(240, 116, 215, 255);
}
else
{
if (screen.Colour != null)
{
screenBgColour = screen.Colour;
@ -486,6 +493,7 @@ namespace DisplayMagicianShared
{
screenBgColour = Color.FromArgb(255, 155, 155, 155);
}
}
g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect);

View File

@ -60,6 +60,26 @@ namespace DisplayMagicianShared.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap amdblack {
get {
object obj = ResourceManager.GetObject("amdblack", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap amdwhite {
get {
object obj = ResourceManager.GetObject("amdwhite", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>
@ -69,5 +89,25 @@ namespace DisplayMagicianShared.Properties {
return ((System.Drawing.Icon)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap nvidiablack {
get {
object obj = ResourceManager.GetObject("nvidiablack", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap nvidiawhite {
get {
object obj = ResourceManager.GetObject("nvidiawhite", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -118,7 +118,19 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="amdblack" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>amdblack.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="amdwhite" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>amdwhite.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="DisplayMagician" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\DisplayMagician.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="nvidiablack" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>nvidiablack.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="nvidiawhite" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>nvidiawhite.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -267,7 +267,7 @@ namespace DisplayMagicianShared.UserControls
}
else
{
// We do these things only if the screen isn't spanned!
// Draw the outline of the monitor
Rectangle outlineRect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect);
@ -275,6 +275,13 @@ namespace DisplayMagicianShared.UserControls
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
if (screen.IsPrimary)
{
//screenBgColour = Color.FromArgb(255, 66, 173, 245);
screenBgColour = Color.FromArgb(240, 116, 215, 255);
}
else
{
if (screen.Colour != null)
{
screenBgColour = screen.Colour;
@ -283,13 +290,19 @@ namespace DisplayMagicianShared.UserControls
{
screenBgColour = Color.FromArgb(255, 155, 155, 155);
}
}
g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect);
Rectangle wordRect = new Rectangle(screen.ScreenX + screenBezel + screenWordBuffer, screen.ScreenY + screenBezel + screenWordBuffer, screen.ScreenWidth - (screenBezel * 2) - (screenWordBuffer * 2), screen.ScreenHeight - (screenBezel * 2) - (screenWordBuffer * 2));
Color wordTextColour = pickTextColorBasedOnBgColour(screenBgColour, lightTextColour, darkTextColour);
// Draw the name of the screen and the size of it
var str = $"{screen.Name}{Environment.NewLine}{screen.ScreenWidth}×{screen.ScreenHeight}";
string str = $"{screen.Name}{Environment.NewLine}{screen.ScreenWidth}×{screen.ScreenHeight}{Environment.NewLine}{screen.DisplayConnector}";
if (screen.IsPrimary)
{
str = $"Primary Display{Environment.NewLine}" + str;
}
DrawString(g, str, wordTextColour, wordRect.Size, wordRect.Location);
// Draw the position of the screen

View File

@ -0,0 +1,475 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
public enum WIN32STATUS
{
ERROR_SUCCESS = 0,
ERROR_ACCESS_DENIED = 5,
ERROR_NOT_SUPPORTED = 50,
ERROR_GEN_FAILURE = 31,
ERROR_INVALID_PARAMETER = 87,
ERROR_INSUFFICIENT_BUFFER = 122,
}
public enum DISPLAYCONFIG_DEVICE_INFO_TYPE
{
DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3,
DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4,
DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5,
DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6,
DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION = 7,
DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION = 8,
DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO = 9,
DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE = 10,
DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL = 11,
}
public enum DISPLAYCONFIG_COLOR_ENCODING
{
DISPLAYCONFIG_COLOR_ENCODING_RGB = 0,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR444 = 1,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR422 = 2,
DISPLAYCONFIG_COLOR_ENCODING_YCBCR420 = 3,
DISPLAYCONFIG_COLOR_ENCODING_INTENSITY = 4,
}
public enum DISPLAYCONFIG_SCALING
{
DISPLAYCONFIG_SCALING_IDENTITY = 1,
DISPLAYCONFIG_SCALING_CENTERED = 2,
DISPLAYCONFIG_SCALING_STRETCHED = 3,
DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
DISPLAYCONFIG_SCALING_CUSTOM = 5,
DISPLAYCONFIG_SCALING_PREFERRED = 128,
}
public enum DISPLAYCONFIG_ROTATION
{
DISPLAYCONFIG_ROTATION_IDENTITY = 1,
DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
}
public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY
{
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = -1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_WIRED = 16,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INDIRECT_VIRTUAL = 17,
DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = unchecked((int)0x80000000),
}
public enum DISPLAYCONFIG_TOPOLOGY_ID
{
DISPLAYCONFIG_TOPOLOGY_INTERNAL = 0x00000001,
DISPLAYCONFIG_TOPOLOGY_CLONE = 0x00000002,
DISPLAYCONFIG_TOPOLOGY_EXTEND = 0x00000004,
DISPLAYCONFIG_TOPOLOGY_EXTERNAL = 0x00000008,
}
public enum DISPLAYCONFIG_PATH
{
DISPLAYCONFIG_PATH_ACTIVE = 0x00000001,
DISPLAYCONFIG_PATH_PREFERRED_UNSCALED = 0x00000004,
DISPLAYCONFIG_PATH_SUPPORT_VIRTUAL_MODE = 0x00000008,
}
public enum DISPLAYCONFIG_SOURCE_FLAGS
{
DISPLAYCONFIG_SOURCE_IN_USE = 0x00000001,
}
public enum DISPLAYCONFIG_TARGET_FLAGS
{
DISPLAYCONFIG_TARGET_IN_USE = 0x00000001,
DISPLAYCONFIG_TARGET_FORCIBLE = 0x00000002,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_BOOT = 0x00000004,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_PATH = 0x00000008,
DISPLAYCONFIG_TARGET_FORCED_AVAILABILITY_SYSTEM = 0x00000010,
DISPLAYCONFIG_TARGET_IS_HMD = 0x00000020,
}
public enum QDC
{
QDC_ALL_PATHS = 0x00000001, // Get all paths
QDC_ONLY_ACTIVE_PATHS = 0x00000002, // Get only the active paths currently in use
QDC_DATABASE_CURRENT = 0x00000004, // Get the current paths in the display database
QDC_VIRTUAL_MODE_AWARE = 0x00000010, // Get the virtual mode aware paths
QDC_INCLUDE_HMD = 0x00000020,
}
public enum DISPLAYCONFIG_SCANLINE_ORDERING
{
DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED,
DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3,
}
public enum DISPLAYCONFIG_PIXELFORMAT
{
DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5,
}
public enum DISPLAYCONFIG_MODE_INFO_TYPE
{
DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2,
DISPLAYCONFIG_MODE_INFO_TYPE_DESKTOP_IMAGE = 3,
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_DEVICE_INFO_HEADER
{
public DISPLAYCONFIG_DEVICE_INFO_TYPE type;
public int size;
public LUID adapterId;
public uint id;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public uint value;
public DISPLAYCONFIG_COLOR_ENCODING colorEncoding;
public int bitsPerColorChannel;
public bool advancedColorSupported => (value & 0x1) == 0x1;
public bool advancedColorEnabled => (value & 0x2) == 0x2;
public bool wideColorEnforced => (value & 0x4) == 0x4;
public bool advancedColorForceDisabled => (value & 0x8) == 0x8;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
public struct LUID
{
public uint LowPart;
public int HighPart;
public long Value => ((long)HighPart << 32) | LowPart;
public override string ToString() => Value.ToString();
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_SOURCE_MODE
{
public uint width;
public uint height;
public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
public POINTL position;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_RATIONAL
{
public uint Numerator;
public uint Denominator;
public override string ToString() => Numerator + " / " + Denominator;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_2DREGION
{
public uint cx;
public uint cy;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_DESKTOP_IMAGE_INFO
{
public POINTL PathSourceSize;
public RECT DesktopImageRegion;
public RECT DesktopImageClip;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO
{
public ulong pixelRate;
public DISPLAYCONFIG_RATIONAL hSyncFreq;
public DISPLAYCONFIG_RATIONAL vSyncFreq;
public DISPLAYCONFIG_2DREGION activeSize;
public DISPLAYCONFIG_2DREGION totalSize;
public uint videoStandard;
public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_TARGET_MODE
{
public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
}
[StructLayout(LayoutKind.Explicit)]
public struct DISPLAYCONFIG_MODE_INFO_union
{
[FieldOffset(0)]
public DISPLAYCONFIG_TARGET_MODE targetMode;
[FieldOffset(0)]
public DISPLAYCONFIG_SOURCE_MODE sourceMode;
[FieldOffset(0)]
public DISPLAYCONFIG_DESKTOP_IMAGE_INFO desktopImageInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_SOURCE_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG_SOURCE_FLAGS statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_TARGET_INFO
{
public LUID adapterId;
public uint id;
public uint modeInfoIdx;
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
public DISPLAYCONFIG_ROTATION rotation;
public DISPLAYCONFIG_SCALING scaling;
public DISPLAYCONFIG_RATIONAL refreshRate;
public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
public bool targetAvailable;
public DISPLAYCONFIG_TARGET_FLAGS statusFlags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_PATH_INFO
{
public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
public DISPLAYCONFIG_PATH flags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DISPLAYCONFIG_MODE_INFO
{
public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
public uint id;
public LUID adapterId;
public DISPLAYCONFIG_MODE_INFO_union info;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_GET_SOURCE_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string viewGdiDeviceName;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS
{
public uint value;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DISPLAYCONFIG_GET_TARGET_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags;
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology;
public ushort edidManufactureId;
public ushort edidProductCodeId;
public uint connectorInstance;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string monitorFriendlyDeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string monitorDevicePath;
}
[StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
public uint Width;
public uint Height;
public DISPLAYCONFIG_TARGET_MODE TargetMode;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DISPLAYCONFIG_GET_ADAPTER_NAME
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string AdapterDevicePath;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
internal struct DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.U4)]
private uint DisableMonitorVirtualResolution;
public bool IsMonitorVirtualResolutionDisabled
{
get => DisableMonitorVirtualResolution > 0;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SET_TARGET_PERSISTENCE
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.U4)]
public uint BootPersistenceOn;
public bool IsBootPersistenceOn
{
get => BootPersistenceOn > 0;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_GET_TARGET_BASE_TYPE
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.U4)]
public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY BaseOutputTechnology;
}
[StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
[MarshalAs(UnmanagedType.U4)]
public uint EnableAdvancedColor;
public bool IsAdvancedColorEnabled
{
get => EnableAdvancedColor > 0;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct DISPLAYCONFIG_SDR_WHITE_LEVEL
{
public DISPLAYCONFIG_DEVICE_INFO_HEADER header;
// SDRWhiteLevel represents a multiplier for standard SDR white
// peak value i.e. 80 nits represented as fixed point.
// To get value in nits use the following conversion
// SDRWhiteLevel in nits = (SDRWhiteLevel / 1000 ) * 80
public ulong SDRWhiteLevel;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
class CCDImport
{
// GetDisplayConfigBufferSizes
[DllImport("user32")]
public static extern int GetDisplayConfigBufferSizes(QDC flags, out int numPathArrayElements, out int numModeInfoArrayElements);
// QueryDisplayConfig
[DllImport("user32")]
public static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, out DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId);
[DllImport("user32")]
public static extern int QueryDisplayConfig(QDC flags, ref int numPathArrayElements, [In, Out] DISPLAYCONFIG_PATH_INFO[] pathArray, ref int numModeInfoArrayElements, [In, Out] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);
// DisplayConfigGetDeviceInfo
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_SOURCE_NAME requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_NAME requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_PREFERRED_NAME requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADAPTER_NAME requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_TARGET_BASE_TYPE requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION requestPacket);
/*[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SET_SUPPORT_VIRTUAL_RESOLUTION requestPacket);
*/
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SET_ADVANCED_COLOR_STATE requestPacket);
[DllImport("user32")]
public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_SDR_WHITE_LEVEL requestPacket);
// DisplayConfigSetDeviceInfo
[DllImport("user32")]
public static extern int DisplayConfigSetDeviceInfo( ref DISPLAYCONFIG_SET_TARGET_PERSISTENCE targetPersistence );
// Have disabled the DisplayConfigSetDeviceInfo options except for SET_TARGET_PERSISTENCE, as per the note
// from https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-displayconfigsetdeviceinfo
// "DisplayConfigSetDeviceInfo can currently only be used to start and stop boot persisted force projection on an analog target."
/*[DllImport("user32")]
public static extern int DisplayConfigSetDeviceInfo( ref DISPLAYCONFIG_SUPPORT_VIRTUAL_RESOLUTION targetSupportVirtualResolution );*/
// SetDisplayConfig
[DllImport("user32")]
public static extern int SetDisplayConfig( [In] uint pathArrayElements, [In] DISPLAYCONFIG_PATH_INFO[] pathArray, [In] uint modeInfoArrayElements, [In] DISPLAYCONFIG_MODE_INFO[] modeInfoArray, [In] QDC flags );
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DisplayMagicianShared.Windows
{
class WindowsCCDLibrary
{
static void Main()
{
var err = CCDImport.GetDisplayConfigBufferSizes(QDC.QDC_ONLY_ACTIVE_PATHS, out var pathCount, out var modeCount);
if (err != 0)
throw new Win32Exception(err);
var paths = new DISPLAYCONFIG_PATH_INFO[pathCount];
var modes = new DISPLAYCONFIG_MODE_INFO[modeCount];
err = CCDImport.QueryDisplayConfig(QDC.QDC_ONLY_ACTIVE_PATHS, ref pathCount, paths, ref modeCount, modes, IntPtr.Zero);
if (err != 0)
throw new Win32Exception(err);
foreach (var path in paths)
{
// get display name
var info = new DISPLAYCONFIG_GET_TARGET_NAME();
info.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
info.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_TARGET_NAME>();
info.header.adapterId = path.targetInfo.adapterId;
info.header.id = path.targetInfo.id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref info);
if (err != 0)
throw new Win32Exception(err);
var colorInfo = new DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO();
colorInfo.header.type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO;
colorInfo.header.size = Marshal.SizeOf<DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO>();
colorInfo.header.adapterId = path.targetInfo.adapterId;
colorInfo.header.id = path.targetInfo.id;
err = CCDImport.DisplayConfigGetDeviceInfo(ref colorInfo);
if (err != 0)
throw new Win32Exception(err);
Console.WriteLine(info.monitorFriendlyDeviceName);
Console.WriteLine(" Advanced Color Supported: " + colorInfo.advancedColorSupported);
Console.WriteLine(" Advanced Color Enabled : " + colorInfo.advancedColorEnabled);
Console.WriteLine();
}
}
}
}