PowerControl: Install custom resolutions (EDID) (experimental feature)

This commit is contained in:
Kamil Trzciński 2023-02-09 12:18:29 +01:00
parent fd93c051fa
commit 862d7afec5
7 changed files with 131 additions and 0 deletions

View file

@ -69,6 +69,34 @@ namespace PowerControl
rootMenu.VisibleChanged += delegate { updateOSD(); };
contextMenu.Items.Add(new ToolStripSeparator());
if (Settings.Default.EnableExperimentalFeatures)
{
var installEDIDItem = contextMenu.Items.Add("Install &Resolutions");
installEDIDItem.Click += delegate { Helpers.AMD.EDID.SetEDID(Resources.CRU_SteamDeck); };
var replaceEDIDItem = contextMenu.Items.Add("Replace &Resolutions");
replaceEDIDItem.Click += delegate { Helpers.AMD.EDID.SetEDID(new byte[0]); Helpers.AMD.EDID.SetEDID(Resources.CRU_SteamDeck); };
var uninstallEDIDItem = contextMenu.Items.Add("Revert &Resolutions");
uninstallEDIDItem.Click += delegate { Helpers.AMD.EDID.SetEDID(new byte[0]); };
contextMenu.Opening += delegate
{
if (ExternalHelpers.DisplayConfig.IsInternalConnected == true)
{
var edid = Helpers.AMD.EDID.GetEDID() ?? new byte[0];
var edidInstalled = Resources.CRU_SteamDeck.SequenceEqual(edid);
installEDIDItem.Visible = edid.Length <= 128;
replaceEDIDItem.Visible = !edidInstalled && edid.Length > 128;
uninstallEDIDItem.Visible = edid.Length > 128;
}
else
{
installEDIDItem.Visible = false;
replaceEDIDItem.Visible = false;
uninstallEDIDItem.Visible = false;
}
};
contextMenu.Items.Add(new ToolStripSeparator());
}
if (startupManager.IsAvailable)
{
var startupItem = new ToolStripMenuItem("Run On Startup");

View file

@ -143,6 +143,30 @@ namespace PowerControl.Helpers.AMD
}
#endregion ADLDisplayInfo
[StructLayout(LayoutKind.Sequential)]
internal struct ADLDisplayEDIDData
{
internal int iSize;
internal int iFlag;
internal int iEDIDSize;
internal int iBlockIndex;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_EDIDDATA_SIZE)]
internal byte[] cEDIDData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
internal int[] iReserved;
};
[StructLayout(LayoutKind.Sequential)]
internal struct ADLDisplayEDIDDataX2
{
internal int iSize;
internal int iFlag;
internal int iEDIDSize;
internal int iIgnored;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)2 * ADL.ADL_MAX_EDIDDATA_SIZE)]
internal byte[] cEDIDData;
};
#region Radeon Image Sharpening
[StructLayout(LayoutKind.Sequential)]
internal struct ADL_RIS_SETTINGS
@ -192,6 +216,8 @@ namespace PowerControl.Helpers.AMD
internal const int ADL_MAX_GLSYNC_PORT_LEDS = 8;
/// <summary> Maximum number of ADLMOdes for the adapter </summary>
internal const int ADL_MAX_NUM_DISPLAYMODES = 1024;
internal const int ADL_MAX_EDIDDATA_SIZE = 256;
internal const int ADL_MAX_EDID_EXTENSION_BLOCKS = 3;
internal const int ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED = 0x00000001;
@ -265,6 +291,12 @@ namespace PowerControl.Helpers.AMD
[DllImport(Atiadlxx_FileName)]
internal static extern int ADL2_RIS_Settings_Set(IntPtr context, int adapterIndex, ADL_RIS_SETTINGS settings, ADL_RIS_NOTFICATION_REASON reason);
[DllImport(Atiadlxx_FileName)]
internal static extern int ADL2_Display_EdidData_Get(IntPtr context, int adapterIndex, int displayIndex, ref ADLDisplayEDIDData edidData);
[DllImport(Atiadlxx_FileName)]
internal static extern int ADL2_Display_EdidData_Set(IntPtr context, int adapterIndex, int displayIndex, ref ADLDisplayEDIDDataX2 edidData);
#endregion DLLImport
#region ADL_Main_Memory_Alloc

View file

@ -0,0 +1,57 @@
using System.Linq;
using System.Runtime.InteropServices;
namespace PowerControl.Helpers.AMD
{
internal class EDID
{
internal static byte[]? GetEDID(int displayIndex = ADL.ADL_DEFAULT_DISPLAY)
{
return ADLContext.WithSafe((context) =>
{
byte[] edid = new byte[0];
for (int block = 0; block < ADL.ADL_MAX_EDID_EXTENSION_BLOCKS; ++block)
{
ADLDisplayEDIDData displayEdidData = new ADLDisplayEDIDData()
{
iSize = Marshal.SizeOf<ADLDisplayEDIDData>(),
iBlockIndex = block,
};
int res = ADL.ADL2_Display_EdidData_Get(context.Context, ADL.ADL_DEFAULT_ADAPTER, ADL.ADL_DEFAULT_DISPLAY, ref displayEdidData);
if (res != 0)
break;
var blockBytes = displayEdidData.cEDIDData.Take(displayEdidData.iEDIDSize);
edid = edid.Concat(blockBytes).ToArray();
}
return edid;
});
}
internal static bool? SetEDID(byte[] value, int displayIndex = ADL.ADL_DEFAULT_DISPLAY)
{
return ADLContext.WithSafe((context) =>
{
var bytes = new byte[ADL.ADL_MAX_EDIDDATA_SIZE * 2];
value.CopyTo(bytes, 0);
var blockData = new ADLDisplayEDIDDataX2()
{
// TODO: Hack to send a full EDID at once
iSize = Marshal.SizeOf<ADLDisplayEDIDData>(),
cEDIDData = bytes,
iEDIDSize = value.Length,
};
int res = ADL.ADL2_Display_EdidData_Set(context.Context,
ADL.ADL_DEFAULT_ADAPTER, ADL.ADL_DEFAULT_DISPLAY,
ref blockData);
return res == 0;
});
}
}
}

View file

@ -60,6 +60,16 @@ namespace PowerControl {
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] CRU_SteamDeck {
get {
object obj = ResourceManager.GetObject("CRU_SteamDeck", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// </summary>

View file

@ -118,6 +118,9 @@
<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="CRU_SteamDeck" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\CRU_SteamDeck.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="traffic-light-outline_light" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\traffic-light-outline_light.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

Binary file not shown.

View file

@ -9,6 +9,7 @@
## 0.6.x
- PowerControl: Install custom resolutions (EDID) (experimental feature)
- SteamController: Add `X360: No Touchpads` profile
- All: Show `Missing RTSS` button to install RTSS
- PowerControl: Retain FPS Limit (proportion) on refresh rate change