diff --git a/PowerControl/Helpers/AMD/ADL.cs b/PowerControl/Helpers/AMD/ADL.cs new file mode 100644 index 0000000..e4b0167 --- /dev/null +++ b/PowerControl/Helpers/AMD/ADL.cs @@ -0,0 +1,272 @@ +#region Copyright + +/******************************************************************************* + Copyright(c) 2008 - 2022 Advanced Micro Devices, Inc. All Rights Reserved. + Copyright (c) 2002 - 2006 ATI Technologies Inc. All Rights Reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF + ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDED BUT NOT LIMITED TO + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + PARTICULAR PURPOSE. + + File: ADL.cs + + Purpose: Implements ADL interface + + Description: Implements some of the methods defined in ADL interface. + + ********************************************************************************/ + +#endregion Copyright + +#region Using + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Threading; +using FARPROC = System.IntPtr; +using HMODULE = System.IntPtr; + +#endregion Using + +#region ATI.ADL + +namespace PowerControl.Helpers.AMD +{ + #region Export Struct + + #region ADLAdapterInfo + /// ADLAdapterInfo Structure + [StructLayout(LayoutKind.Sequential)] + internal struct ADLAdapterInfo + { + /// The size of the structure + int Size; + /// Adapter Index + internal int AdapterIndex; + /// Adapter UDID + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string UDID; + /// Adapter Bus Number + internal int BusNumber; + /// Adapter Driver Number + internal int DriverNumber; + /// Adapter Function Number + internal int FunctionNumber; + /// Adapter Vendor ID + internal int VendorID; + /// Adapter Adapter name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string AdapterName; + /// Adapter Display name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string DisplayName; + /// Adapter Present status + internal int Present; + /// Adapter Exist status + internal int Exist; + /// Adapter Driver Path + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string DriverPath; + /// Adapter Driver Ext Path + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string DriverPathExt; + /// Adapter PNP String + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string PNPString; + /// OS Display Index + internal int OSDisplayIndex; + } + + + /// ADLAdapterInfo Array + [StructLayout(LayoutKind.Sequential)] + internal struct ADLAdapterInfoArray + { + /// ADLAdapterInfo Array + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_ADAPTERS)] + internal ADLAdapterInfo[] ADLAdapterInfo; + } + #endregion ADLAdapterInfo + + + #region ADLDisplayInfo + /// ADLDisplayID Structure + [StructLayout(LayoutKind.Sequential)] + internal struct ADLDisplayID + { + /// Display Logical Index + internal int DisplayLogicalIndex; + /// Display Physical Index + internal int DisplayPhysicalIndex; + /// Adapter Logical Index + internal int DisplayLogicalAdapterIndex; + /// Adapter Physical Index + internal int DisplayPhysicalAdapterIndex; + } + + /// ADLDisplayInfo Structure + [StructLayout(LayoutKind.Sequential)] + internal struct ADLDisplayInfo + { + /// Display Index + internal ADLDisplayID DisplayID; + /// Display Controller Index + internal int DisplayControllerIndex; + /// Display Name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string DisplayName; + /// Display Manufacturer Name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)] + internal string DisplayManufacturerName; + /// Display Type : < The Display type. CRT, TV,CV,DFP are some of display types, + internal int DisplayType; + /// Display output type + internal int DisplayOutputType; + /// Connector type + internal int DisplayConnector; + /// Indicating the display info bits' mask. + internal int DisplayInfoMask; + /// Indicating the display info value. + internal int DisplayInfoValue; + } + + /// ADLAdapterInfo Array + [StructLayout(LayoutKind.Sequential)] + internal class ADLDisplayInfoArray + { + /// ADLAdapterInfo Array + [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_DISPLAYS)] + internal ADLDisplayInfo[] ADLAdapterInfo; + } + #endregion ADLDisplayInfo + + #endregion Export Struct + + #region ADL Class + /// ADL Class + internal static class ADL + { + internal const int ADL_DEFAULT_ADAPTER = 0; + internal const int ADL_DEFAULT_DISPLAY = 0; + + #region Internal Constant + /// Define the maximum path + internal const int ADL_MAX_PATH = 256; + /// Define the maximum adapters + internal const int ADL_MAX_ADAPTERS = 40 /* 150 */; + /// Define the maximum displays + internal const int ADL_MAX_DISPLAYS = 40 /* 150 */; + /// Define the maximum device name length + internal const int ADL_MAX_DEVICENAME = 32; + /// Define the successful + internal const int ADL_SUCCESS = 0; + /// Define the failure + internal const int ADL_FAIL = -1; + /// Define the driver ok + internal const int ADL_DRIVER_OK = 0; + /// Maximum number of GL-Sync ports on the GL-Sync module + internal const int ADL_MAX_GLSYNC_PORTS = 8; + /// Maximum number of GL-Sync ports on the GL-Sync module + internal const int ADL_MAX_GLSYNC_PORT_LEDS = 8; + /// Maximum number of ADLMOdes for the adapter + internal const int ADL_MAX_NUM_DISPLAYMODES = 1024; + + internal const int ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED = 0x00000001; + + #endregion Internal Constant + + #region Internal Constant + /// Atiadlxx_FileName + internal const string Atiadlxx_FileName = "atiadlxx.dll"; + /// Kernel32_FileName + internal const string Kernel32_FileName = "kernel32.dll"; + #endregion Internal Constant + + #region Export Delegates + /// ADL Memory allocation function allows ADL to callback for memory allocation + /// input size + /// retrun ADL Error Code + internal delegate IntPtr ADL_Main_Memory_Alloc(int size); + #endregion + + #region DLLImport + [DllImport(Kernel32_FileName)] + internal static extern HMODULE GetModuleHandle (string moduleName); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Main_Control_Create(ADL_Main_Memory_Alloc callback, int enumConnectedAdapters, out IntPtr context); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Main_Control_Destroy (IntPtr context); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Main_Control_IsFunctionValid (IntPtr context, HMODULE module, string procName); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Adapter_NumberOfAdapters_Get (IntPtr context, out int numAdapters); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Adapter_AdapterInfo_Get (IntPtr context, out ADLAdapterInfoArray info, int inputSize); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Adapter_Active_Get(IntPtr context, int adapterIndex, out int status); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_DisplayInfo_Get(IntPtr context, int adapterIndex, out int numDisplays, out IntPtr displayInfoArray, int forceDetect); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_DFP_GPUScalingEnable_Get(IntPtr context, int adapterIndex, int displayIndex, out int support, out int current, out int default_); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_DFP_GPUScalingEnable_Set(IntPtr context, int adapterIndex, int displayIndex, int current); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_PreservedAspectRatio_Get(IntPtr context, int adapterIndex, int displayIndex, out int support, out int current, out int default_); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_PreservedAspectRatio_Set(IntPtr context, int adapterIndex, int displayIndex, int current); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_ImageExpansion_Get(IntPtr context, int adapterIndex, int displayIndex, out int support, out int current, out int default_); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_ImageExpansion_Set(IntPtr context, int adapterIndex, int displayIndex, int current); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_SCE_State_Get(IntPtr context, int adapterIndex, int displayIndex, out int current, out int support, out int default_); + + [DllImport(Atiadlxx_FileName)] + internal static extern int ADL2_Display_SCE_State_Set(IntPtr context, int adapterIndex, int displayIndex, int current); + #endregion DLLImport + + #region ADL_Main_Memory_Alloc + /// Build in memory allocation function + /// input size + /// return the memory buffer + internal static IntPtr ADL_Main_Memory_Alloc_(int size) + { + IntPtr result = Marshal.AllocCoTaskMem(size); + return result; + } + #endregion ADL_Main_Memory_Alloc + + #region ADL_Main_Memory_Free + /// Build in memory free function + /// input buffer + internal static void ADL_Main_Memory_Free(IntPtr buffer) + { + if (IntPtr.Zero != buffer) + { + Marshal.FreeCoTaskMem(buffer); + } + } + #endregion ADL_Main_Memory_Free + } + #endregion ADL Class +} + +#endregion ATI.ADL \ No newline at end of file diff --git a/PowerControl/Helpers/AMD/ADLContext.cs b/PowerControl/Helpers/AMD/ADLContext.cs new file mode 100644 index 0000000..3d0c3e7 --- /dev/null +++ b/PowerControl/Helpers/AMD/ADLContext.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace PowerControl.Helpers.AMD +{ + internal class ADLContext : IDisposable + { + public IntPtr Context { get; private set; } + + public ADLContext() + { + IntPtr context = IntPtr.Zero; + WithSafe(() => ADL.ADL2_Main_Control_Create(ADL.ADL_Main_Memory_Alloc_, 1, out context), true); + Context = context; + } + + public bool IsValid + { + get { return Context != IntPtr.Zero; } + } + + public ADLAdapterInfo[]? AdapterInfos + { + get + { + int res = ADL.ADL2_Adapter_NumberOfAdapters_Get(Context, out var numAdapters); + if (res != 0) + return null; + + res = ADL.ADL2_Adapter_AdapterInfo_Get(Context, + out var adapters, + Marshal.SizeOf()); + if (res != 0) + return null; + + return adapters.ADLAdapterInfo.Take(numAdapters).ToArray(); + } + } + + public IEnumerable DisplayInfos + { + get + { + foreach (var adapter in AdapterInfos) + { + if (adapter.Present == 0) + continue; + + foreach (var display in GetDisplayInfos(adapter.AdapterIndex)) + { + if ((display.DisplayInfoValue & ADL.ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED) != ADL.ADL_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED) + continue; + + yield return display; + } + } + } + } + + public IEnumerable GetDisplayInfos(int adapterIndex) + { + int res = ADL.ADL2_Display_DisplayInfo_Get(Context, adapterIndex, out var numDisplays, out var displays, 0); + if (res != 0) + yield break; + + try + { + int sizeOf = Marshal.SizeOf(); + + for (int i = 0; i < numDisplays; i++) + { + var display = Marshal.PtrToStructure(IntPtr.Add(displays, i * sizeOf)); + // TODO: why even though we pass adapterIndex? + if (display.DisplayID.DisplayLogicalAdapterIndex != adapterIndex) + continue; + yield return display; + } + } + finally + { + ADL.ADL_Main_Memory_Free(displays); + } + } + + ~ADLContext() + { + Dispose(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + if (Context != IntPtr.Zero) + { + WithSafe(() => ADL.ADL2_Main_Control_Destroy(Context)); + Context = IntPtr.Zero; + } + } + + private static ADLContext? instance; + private static readonly Mutex mutex = new Mutex(); + + public static T? WithSafe(Func func, bool useInstance = false) + { + if (useInstance) + { + if (!mutex.WaitOne(200)) + return default; + + try + { + if (instance == null) + instance = new ADLContext(); + return instance.WithSafe(() => func(instance)); + } + finally + { + mutex.ReleaseMutex(); + } + } + else + { + using(var context = new ADLContext()) + { + return context.WithSafe(() => func(context)); + } + } + } + + public T? WithSafe(Func func, bool force = false) + { + if (!IsValid && !force) + return default; + + try + { + return func(); + } + catch (DllNotFoundException e) { TraceLine("ADL: Method not found: {0}", e); } + catch (EntryPointNotFoundException e) { TraceLine("ADL: Entry point not found: {0}", e); } + catch (Exception e) { TraceLine("ADL: Generic Exception: {0}", e); } + + return default; + } + + private static void TraceLine(string format, params object?[]? arg) + { + Trace.WriteLine(string.Format(format, arg)); + } + } +} diff --git a/PowerControl/Helpers/AMD/AMDAdrenaline.cs b/PowerControl/Helpers/AMD/AMDAdrenaline.cs deleted file mode 100644 index 2d8a165..0000000 --- a/PowerControl/Helpers/AMD/AMDAdrenaline.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.Win32; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace PowerControl.Helpers.GPU -{ - internal class AMDAdrenaline - { - // TODO: This CLSID is likely to change over time and be broken - // pnputil /enum-devices /class Display - const string GPUDriverKey = "SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\0000"; - const string DriverDesc = "DriverDesc"; - const string ExpectedDriverDesc = "AMD Custom GPU 0405"; - const string GPUScaling = "GPUScaling00"; - - internal static bool IsGPUScalingEnabled() - { - try - { - var registry = Registry.LocalMachine.OpenSubKey(GPUDriverKey); - if (registry == null) - return false; - - var driverDesc = registry.GetValue(DriverDesc); - if (driverDesc is string && (string)driverDesc != ExpectedDriverDesc) - return false; - - var scalingBytes = registry.GetValue(GPUScaling); - if (scalingBytes is not byte[]) - return false; - - var scaling = BitConverter.ToUInt32((byte[])scalingBytes); - return scaling == 1; - } - catch - { - return false; - } - } - } -} diff --git a/PowerControl/Helpers/AMD/DCE.cs b/PowerControl/Helpers/AMD/DCE.cs new file mode 100644 index 0000000..7b88c48 --- /dev/null +++ b/PowerControl/Helpers/AMD/DCE.cs @@ -0,0 +1,56 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PowerControl.Helpers.AMD +{ + internal class DCE + { + internal enum Mode + { + Normal = 1, + Vivid + } + + internal static Mode? Current + { + get + { + return ADLContext.WithSafe((context) => + { + int res = ADL.ADL2_Display_SCE_State_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var current, out var support, out _); + + if (res == 0 && support == 1) + return current == 2 ? Mode.Vivid : Mode.Normal; + + return (DCE.Mode?)null; + }); + } + set + { + ADLContext.WithSafe((context) => + { + if (value is null) + return false; + + ADL.ADL2_Display_SCE_State_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + (int)value + ); + + return true; + }); + } + } + } +} diff --git a/PowerControl/Helpers/AMD/GPUScaling.cs b/PowerControl/Helpers/AMD/GPUScaling.cs new file mode 100644 index 0000000..b288c71 --- /dev/null +++ b/PowerControl/Helpers/AMD/GPUScaling.cs @@ -0,0 +1,184 @@ +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PowerControl.Helpers.AMD +{ + internal class GPUScaling + { + public enum ScalingMode + { + AspectRatio, + FullPanel, + Centered + } + + internal static bool SafeResolutionChange + { + get { return Enabled; } + } + + internal static bool IsSupported + { + get + { + return ADLContext.WithSafe((context) => + { + int res = ADL.ADL2_DFP_GPUScalingEnable_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var support, out _, out _); + + if (res == 0 && support == 1) + return true; + + return false; + }); + } + } + + internal static bool Enabled + { + get + { + return ADLContext.WithSafe((context) => + { + int res = ADL.ADL2_DFP_GPUScalingEnable_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var support, out var current, out _); + if (res == 0 && support == 1 && current == 1) + return true; + + return false; + }); + } + set + { + ADLContext.WithSafe((context) => + { + ADL.ADL2_DFP_GPUScalingEnable_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var _, out var current, out _); + if (current == (value ? 1 : 0)) + return true; + + ADL.ADL2_DFP_GPUScalingEnable_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + value ? 1 : 0 + ); + + return true; + }); + } + } + + internal static ScalingMode? Mode + { + get + { + return ADLContext.WithSafe((context) => + { + int resAR = ADL.ADL2_Display_PreservedAspectRatio_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var supportAR, out var ar, out _); + int resIE = ADL.ADL2_Display_ImageExpansion_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var supportIE, out var ie, out _); + + if (resAR != 0 || resIE != 0) + return default(ScalingMode?); + + TraceLine("GPUScaling: ar={0}, ie={1}", + supportAR > 0 ? ar : -1, supportIE > 0 ? ie : -1); + + if (ar == 1) + return ScalingMode.AspectRatio; + else if (ie == 1) + return ScalingMode.FullPanel; + else if (ie == 0 && supportIE == 1) + return ScalingMode.Centered; + + return default(ScalingMode?); + }); + } + set + { + ADLContext.WithSafe((context) => + { + int resGS = ADL.ADL2_DFP_GPUScalingEnable_Get( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + out var _, out var current, out _); + if (current == 0) + { + resGS = ADL.ADL2_DFP_GPUScalingEnable_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + 1 + ); + } + + int resAR = -1; + int resIE = -1; + + switch (value) + { + case ScalingMode.FullPanel: + resIE = ADL.ADL2_Display_ImageExpansion_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + 1 + ); + break; + + case ScalingMode.AspectRatio: + resAR = ADL.ADL2_Display_PreservedAspectRatio_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + 1 + ); + break; + + case ScalingMode.Centered: + resIE = ADL.ADL2_Display_ImageExpansion_Set( + context.Context, + ADL.ADL_DEFAULT_ADAPTER, + ADL.ADL_DEFAULT_DISPLAY, + 0 + ); + break; + } + + TraceLine("GPUScaling: mode={0} => resAR={1}, resIE={2}, resGS={3}", + value, resAR, resIE, resGS); + + return true; + }); + } + } + + private static void TraceLine(string format, params object?[]? arg) + { + Trace.WriteLine(string.Format(format, arg)); + } + } +} diff --git a/PowerControl/Helpers/AMD/RadeonSoftware.cs b/PowerControl/Helpers/AMD/RadeonSoftware.cs new file mode 100644 index 0000000..189e09d --- /dev/null +++ b/PowerControl/Helpers/AMD/RadeonSoftware.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PowerControl.Helpers.AMD +{ + public class RadeonSoftware + { + public static void Kill() + { + foreach (var process in Process.GetProcessesByName("RadeonSoftware.exe")) + { + try { process.Kill(); } + catch { } + } + } + } +} diff --git a/PowerControl/Helpers/DisplayResolutionController.cs b/PowerControl/Helpers/DisplayResolutionController.cs index 3e31f08..996d547 100644 --- a/PowerControl/Helpers/DisplayResolutionController.cs +++ b/PowerControl/Helpers/DisplayResolutionController.cs @@ -56,7 +56,7 @@ namespace PowerControl.Helpers } } - private static DEVMODE? CurrentDisplaySettings() + internal static DEVMODE? CurrentDisplaySettings() { DEVMODE dm = new DEVMODE(); if (EnumDisplaySettings(null, ENUM_CURRENT_SETTINGS, ref dm)) @@ -64,6 +64,17 @@ namespace PowerControl.Helpers return null; } + public static bool SetDisplaySettings(DEVMODE? best) + { + if (best == null) + return false; + + DEVMODE dm = best.Value; + + var dispChange = ChangeDisplaySettingsEx(null, ref dm, IntPtr.Zero, ChangeDisplaySettingsFlags.CDS_NONE, IntPtr.Zero); + return dispChange == DISP_CHANGE.Successful; + } + public static DisplayResolution[] GetAllResolutions() { return FindAllDisplaySettings() @@ -174,7 +185,7 @@ namespace PowerControl.Helpers } [Flags()] - enum DM : int + internal enum DM : int { Orientation = 0x1, PaperSize = 0x2, @@ -208,14 +219,14 @@ namespace PowerControl.Helpers DisplayFixedOutput = 0x20000000 } - struct POINTL + internal struct POINTL { public Int32 x; public Int32 y; }; [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] - struct DEVMODE + internal struct DEVMODE { public const int CCHDEVICENAME = 32; public const int CCHFORMNAME = 32; diff --git a/PowerControl/MenuStack.cs b/PowerControl/MenuStack.cs index b1d1485..2b3abcc 100644 --- a/PowerControl/MenuStack.cs +++ b/PowerControl/MenuStack.cs @@ -1,7 +1,9 @@ using CommonHelpers; using PowerControl.Helpers; +using PowerControl.Helpers.AMD; using PowerControl.Helpers.GPU; using System.Diagnostics; +using static PowerControl.Helpers.AMD.DCE; namespace PowerControl { @@ -45,12 +47,13 @@ namespace PowerControl return Helpers.AudioManager.GetMasterVolume(5.0); } }, + new Menu.MenuItemSeparator(), new Menu.MenuItemWithOptions() { Name = "Resolution", ApplyDelay = 1000, ResetValue = () => { - if (!AMDAdrenaline.IsGPUScalingEnabled() && !Settings.Default.EnableExperimentalFeatures) + if (!GPUScaling.SafeResolutionChange && !Settings.Default.EnableExperimentalFeatures) return null; return DisplayResolutionController.GetAllResolutions().Last(); }, @@ -63,7 +66,7 @@ namespace PowerControl }, CurrentValue = delegate() { - if (!AMDAdrenaline.IsGPUScalingEnabled() && !Settings.Default.EnableExperimentalFeatures) + if (!GPUScaling.SafeResolutionChange && !Settings.Default.EnableExperimentalFeatures) return null; return DisplayResolutionController.GetResolution(); }, @@ -148,6 +151,61 @@ namespace PowerControl } }, new Menu.MenuItemWithOptions() + { + Name = "GPU Scaling", + ApplyDelay = 1000, + Options = Enum.GetValues().Cast().Prepend("Off").ToArray(), + CurrentValue = delegate() + { + if (!GPUScaling.IsSupported) + return null; + if (!GPUScaling.Enabled) + return "Off"; + return GPUScaling.Mode; + }, + ApplyValue = delegate(object selected) + { + if (!GPUScaling.IsSupported) + return null; + + if (selected is GPUScaling.ScalingMode) + GPUScaling.Mode = (GPUScaling.ScalingMode)selected; + else + GPUScaling.Enabled = false; + + // Since the RadeonSoftware will try to revert values + RadeonSoftware.Kill(); + + Root["Resolution"].Update(); + Root["Refresh Rate"].Update(); + Root["FPS Limit"].Update(); + + if (!GPUScaling.Enabled) + return "Off"; + return GPUScaling.Mode; + } + }, + new Menu.MenuItemWithOptions() + { + Name = "Colors", + ApplyDelay = 1000, + Options = Enum.GetValues().Cast().ToList(), + CurrentValue = delegate() + { + return DCE.Current; + }, + ApplyValue = delegate(object selected) + { + if (DCE.Current is null) + return null; + + DCE.Current = (DCE.Mode)selected; + RadeonSoftware.Kill(); + return DCE.Current; + } + }, + new Menu.MenuItemSeparator(), + new Menu.MenuItemWithOptions() { Name = "TDP", Options = { "3W", "4W", "5W", "6W", "7W", "8W", "10W", "12W", "15W" }, diff --git a/RELEASE.md b/RELEASE.md index f00ad20..f2df0e7 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -8,5 +8,6 @@ - Show Full OSD if in PowerControl mode - Highly risky: Allow to change CPU and GPU frequency (enable `EnableExperimentalFeatures` in `PowerControl.dll.config`) - Show CPU/GPU frequency in Full overlay +- Allow to control GPU Scaling and Display Color Correction If you found it useful buy me [Ko-fi](https://ko-fi.com/ayufan).