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