mirror of
https://github.com/ayufan/steam-deck-tools.git
synced 2026-01-26 10:14:21 +01:00
Add GPU scaling and Vivid Gaming selection
This commit is contained in:
parent
ed6cc9ea14
commit
af52e41aef
272
PowerControl/Helpers/AMD/ADL.cs
Normal file
272
PowerControl/Helpers/AMD/ADL.cs
Normal file
|
|
@ -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
|
||||
/// <summary> ADLAdapterInfo Structure</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ADLAdapterInfo
|
||||
{
|
||||
/// <summary>The size of the structure</summary>
|
||||
int Size;
|
||||
/// <summary> Adapter Index</summary>
|
||||
internal int AdapterIndex;
|
||||
/// <summary> Adapter UDID</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string UDID;
|
||||
/// <summary> Adapter Bus Number</summary>
|
||||
internal int BusNumber;
|
||||
/// <summary> Adapter Driver Number</summary>
|
||||
internal int DriverNumber;
|
||||
/// <summary> Adapter Function Number</summary>
|
||||
internal int FunctionNumber;
|
||||
/// <summary> Adapter Vendor ID</summary>
|
||||
internal int VendorID;
|
||||
/// <summary> Adapter Adapter name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string AdapterName;
|
||||
/// <summary> Adapter Display name</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string DisplayName;
|
||||
/// <summary> Adapter Present status</summary>
|
||||
internal int Present;
|
||||
/// <summary> Adapter Exist status</summary>
|
||||
internal int Exist;
|
||||
/// <summary> Adapter Driver Path</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string DriverPath;
|
||||
/// <summary> Adapter Driver Ext Path</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string DriverPathExt;
|
||||
/// <summary> Adapter PNP String</summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string PNPString;
|
||||
/// <summary> OS Display Index</summary>
|
||||
internal int OSDisplayIndex;
|
||||
}
|
||||
|
||||
|
||||
/// <summary> ADLAdapterInfo Array</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ADLAdapterInfoArray
|
||||
{
|
||||
/// <summary> ADLAdapterInfo Array </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_ADAPTERS)]
|
||||
internal ADLAdapterInfo[] ADLAdapterInfo;
|
||||
}
|
||||
#endregion ADLAdapterInfo
|
||||
|
||||
|
||||
#region ADLDisplayInfo
|
||||
/// <summary> ADLDisplayID Structure</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ADLDisplayID
|
||||
{
|
||||
/// <summary> Display Logical Index </summary>
|
||||
internal int DisplayLogicalIndex;
|
||||
/// <summary> Display Physical Index </summary>
|
||||
internal int DisplayPhysicalIndex;
|
||||
/// <summary> Adapter Logical Index </summary>
|
||||
internal int DisplayLogicalAdapterIndex;
|
||||
/// <summary> Adapter Physical Index </summary>
|
||||
internal int DisplayPhysicalAdapterIndex;
|
||||
}
|
||||
|
||||
/// <summary> ADLDisplayInfo Structure</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ADLDisplayInfo
|
||||
{
|
||||
/// <summary> Display Index </summary>
|
||||
internal ADLDisplayID DisplayID;
|
||||
/// <summary> Display Controller Index </summary>
|
||||
internal int DisplayControllerIndex;
|
||||
/// <summary> Display Name </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string DisplayName;
|
||||
/// <summary> Display Manufacturer Name </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)ADL.ADL_MAX_PATH)]
|
||||
internal string DisplayManufacturerName;
|
||||
/// <summary> Display Type : < The Display type. CRT, TV,CV,DFP are some of display types,</summary>
|
||||
internal int DisplayType;
|
||||
/// <summary> Display output type </summary>
|
||||
internal int DisplayOutputType;
|
||||
/// <summary> Connector type</summary>
|
||||
internal int DisplayConnector;
|
||||
///<summary> Indicating the display info bits' mask.<summary>
|
||||
internal int DisplayInfoMask;
|
||||
///<summary> Indicating the display info value.<summary>
|
||||
internal int DisplayInfoValue;
|
||||
}
|
||||
|
||||
/// <summary> ADLAdapterInfo Array</summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class ADLDisplayInfoArray
|
||||
{
|
||||
/// <summary> ADLAdapterInfo Array </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)ADL.ADL_MAX_DISPLAYS)]
|
||||
internal ADLDisplayInfo[] ADLAdapterInfo;
|
||||
}
|
||||
#endregion ADLDisplayInfo
|
||||
|
||||
#endregion Export Struct
|
||||
|
||||
#region ADL Class
|
||||
/// <summary> ADL Class</summary>
|
||||
internal static class ADL
|
||||
{
|
||||
internal const int ADL_DEFAULT_ADAPTER = 0;
|
||||
internal const int ADL_DEFAULT_DISPLAY = 0;
|
||||
|
||||
#region Internal Constant
|
||||
/// <summary> Define the maximum path</summary>
|
||||
internal const int ADL_MAX_PATH = 256;
|
||||
/// <summary> Define the maximum adapters</summary>
|
||||
internal const int ADL_MAX_ADAPTERS = 40 /* 150 */;
|
||||
/// <summary> Define the maximum displays</summary>
|
||||
internal const int ADL_MAX_DISPLAYS = 40 /* 150 */;
|
||||
/// <summary> Define the maximum device name length</summary>
|
||||
internal const int ADL_MAX_DEVICENAME = 32;
|
||||
/// <summary> Define the successful</summary>
|
||||
internal const int ADL_SUCCESS = 0;
|
||||
/// <summary> Define the failure</summary>
|
||||
internal const int ADL_FAIL = -1;
|
||||
/// <summary> Define the driver ok</summary>
|
||||
internal const int ADL_DRIVER_OK = 0;
|
||||
/// <summary> Maximum number of GL-Sync ports on the GL-Sync module </summary>
|
||||
internal const int ADL_MAX_GLSYNC_PORTS = 8;
|
||||
/// <summary> Maximum number of GL-Sync ports on the GL-Sync module </summary>
|
||||
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_DISPLAY_DISPLAYINFO_DISPLAYCONNECTED = 0x00000001;
|
||||
|
||||
#endregion Internal Constant
|
||||
|
||||
#region Internal Constant
|
||||
/// <summary> Atiadlxx_FileName </summary>
|
||||
internal const string Atiadlxx_FileName = "atiadlxx.dll";
|
||||
/// <summary> Kernel32_FileName </summary>
|
||||
internal const string Kernel32_FileName = "kernel32.dll";
|
||||
#endregion Internal Constant
|
||||
|
||||
#region Export Delegates
|
||||
/// <summary> ADL Memory allocation function allows ADL to callback for memory allocation</summary>
|
||||
/// <param name="size">input size</param>
|
||||
/// <returns> retrun ADL Error Code</returns>
|
||||
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
|
||||
/// <summary> Build in memory allocation function</summary>
|
||||
/// <param name="size">input size</param>
|
||||
/// <returns>return the memory buffer</returns>
|
||||
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
|
||||
/// <summary> Build in memory free function</summary>
|
||||
/// <param name="buffer">input buffer</param>
|
||||
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
|
||||
156
PowerControl/Helpers/AMD/ADLContext.cs
Normal file
156
PowerControl/Helpers/AMD/ADLContext.cs
Normal file
|
|
@ -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<ADLAdapterInfoArray>());
|
||||
if (res != 0)
|
||||
return null;
|
||||
|
||||
return adapters.ADLAdapterInfo.Take(numAdapters).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<ADLDisplayInfo> 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<ADLDisplayInfo> 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<ADLDisplayInfo>();
|
||||
|
||||
for (int i = 0; i < numDisplays; i++)
|
||||
{
|
||||
var display = Marshal.PtrToStructure<ADLDisplayInfo>(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<T>(Func<ADLContext, T?> 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<T>(Func<T?> 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
PowerControl/Helpers/AMD/DCE.cs
Normal file
56
PowerControl/Helpers/AMD/DCE.cs
Normal file
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
184
PowerControl/Helpers/AMD/GPUScaling.cs
Normal file
184
PowerControl/Helpers/AMD/GPUScaling.cs
Normal file
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
21
PowerControl/Helpers/AMD/RadeonSoftware.cs
Normal file
21
PowerControl/Helpers/AMD/RadeonSoftware.cs
Normal file
|
|
@ -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 { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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<GPUScaling.ScalingMode>().Cast<object>().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<DCE.Mode>().Cast<object>().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" },
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
Loading…
Reference in a new issue