using CustomResolution.Hooks; using Dalamud.Game.ClientState.Keys; using Dalamud.Game.Config; using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; using FFXIVClientStructs.FFXIV.Client.Graphics.Render; using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.Interop; using ImGuiNET; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Xml.Linq; using TerraFX.Interop.Windows; using static TerraFX.Interop.Windows.Windows; namespace CustomResolution; public unsafe class GameSizeState : IDisposable { private bool _wasEnabled = false; private bool? _forceDynRezoConfig; public bool ConfigDynRezo { get; private set; } public ResolutionScalingMode ConfigGraphicsRezoType { get; private set; } public float ConfigGraphicsRezoScale { get; private set; } public string DebugInfo { get; private set; } = ""; public void Dispose() { Service.Framework.RunOnFrameworkThread(Update); } public void ForceDynRezoConfig(bool value) { _forceDynRezoConfig = value; } public void Update() { ref var cfg = ref Service.Config._.Game; if (_forceDynRezoConfig.HasValue) { Service.GameConfig.System.Set(SystemConfigOption.DynamicRezoType.ToString(), _forceDynRezoConfig.Value ? 1U : 0U); _forceDynRezoConfig = null; } ConfigDynRezo = Service.GameConfig.System.GetUInt(SystemConfigOption.DynamicRezoType.ToString()) != 0U; // GameConfig starts with FSR at 0; GraphicsConfig starts with FSR at 1 ConfigGraphicsRezoType = (ResolutionScalingMode) (Service.GameConfig.System.GetUInt(SystemConfigOption.GraphicsRezoUpscaleType.ToString()) + 1); ConfigGraphicsRezoScale = Service.GameConfig.System.GetUInt(SystemConfigOption.GraphicsRezoScale.ToString()) / 100f; var dev = Device.Instance(); var gfx = GraphicsConfig.Instance(); var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance(); //Service.PluginLog.Debug($"GraphicsRezoScale 0x{(long) (IntPtr) (&gfx->GraphicsRezoScale):X16}"); //Service.PluginLog.Debug($"RTM 0x{(long) (IntPtr) rtm:X16}"); if (Service.DebugConfig.IsDebug) { DebugInfo = @$"DR {gfx->DynamicRezoEnable} RTM {rtm->Resolution_Width} x {rtm->Resolution_Height} RTM H {rtm->DynamicResolutionActualTargetHeight} {rtm->DynamicResolutionTargetHeight} {rtm->DynamicResolutionMaximumHeight} {rtm->DynamicResolutionMinimumHeight} RTM S {rtm->GraphicsRezoScalePrev} {rtm->GraphicsRezoScaleGlassWidth} {rtm->GraphicsRezoScaleGlassHeight} {rtm->GraphicsRezoScaleGlassWidth} {rtm->GraphicsRezoScaleGlassHeight}"; } bool unloading = Service.Plugin.Unloading; bool enabled = !unloading && cfg.IsEnabled; if (enabled || _wasEnabled) { gfx->GraphicsRezoScale = enabled ? cfg.Scale : ConfigGraphicsRezoScale; gfx->DynamicRezoEnable = (byte) (ConfigDynRezo || enabled ? 1 : 0); if (enabled) { gfx->GraphicsRezoUpscaleType = (byte) (cfg.Scale <= 1f ? Service.Config._.ResolutionScalingMode : ResolutionScalingMode.Fast); } else { gfx->GraphicsRezoUpscaleType = (byte) ConfigGraphicsRezoType; } _wasEnabled = enabled; } if (enabled) { rtm->DynamicResolutionMinimumHeight = rtm->DynamicResolutionMaximumHeight; } /* rtm->Resolution_Width = (ushort) (dev->Width * gfx->GraphicsRezoScale); rtm->Resolution_Height = (ushort) (dev->Height * gfx->GraphicsRezoScale); rtm->DynamicResolutionActualTargetHeight = (ushort) (dev->Height * gfx->GraphicsRezoScale); rtm->DynamicResolutionTargetHeight = (ushort) (dev->Height * gfx->GraphicsRezoScale); rtm->DynamicResolutionMaximumHeight = (ushort) (dev->Height * gfx->GraphicsRezoScale); rtm->DynamicResolutionMinimumHeight = (ushort) (dev->Height * gfx->GraphicsRezoScale); */ } // RenderTargetManager is updated very sporadically, and some fields we need flew out // https://github.com/aers/FFXIVClientStructs/commit/589df2aa5cd9c98b4d62269034cd6da903f49b5f#diff-8e7d9b03cb91cb07a8d7b463b5be4672793a328703bde393e7acd890822a72cf [StructLayout(LayoutKind.Explicit)] private struct RenderTargetManagerEx { [FieldOffset(0)] public RenderTargetManager _; #if CRES_CLEAN || false public ref uint Resolution_Width => ref _.Resolution_Width; public ref uint Resolution_Height => ref _.Resolution_Height; public ref ushort DynamicResolutionActualTargetHeight => ref _.DynamicResolutionActualTargetHeight; public ref ushort DynamicResolutionTargetHeight => ref _.DynamicResolutionTargetHeight; public ref ushort DynamicResolutionMaximumHeight => ref _.DynamicResolutionMaximumHeight; public ref ushort DynamicResolutionMinimumHeight => ref _.DynamicResolutionMinimumHeight; public ref float GraphicsRezoScale => ref _.GraphicsRezoScale; #else [FieldOffset(0x428)] public uint Resolution_Width; [FieldOffset(0x428 + 0x4)] public uint Resolution_Height; [FieldOffset(0x6F0 + 2 * 0)] public ushort DynamicResolutionActualTargetHeight; [FieldOffset(0x6F0 + 2 * 1)] public ushort DynamicResolutionTargetHeight; [FieldOffset(0x6F0 + 2 * 2)] public ushort DynamicResolutionMaximumHeight; [FieldOffset(0x6F0 + 2 * 3)] public ushort DynamicResolutionMinimumHeight; [FieldOffset(0x70C + 4 * 0)] public float GraphicsRezoScalePrev; [FieldOffset(0x70C + 4 * 1)] public float GraphicsRezoScaleGlassWidth; [FieldOffset(0x70C + 4 * 2)] public float GraphicsRezoScaleGlassHeight; [FieldOffset(0x70C + 4 * 3)] public float GraphicsRezoScaleUnk1; [FieldOffset(0x70C + 4 * 4)] public float GraphicsRezoScaleUnk2; #endif } }