core: Send WM_ resize msgs instead of requesting device resize

This commit is contained in:
Jade Macho 2025-06-28 21:38:35 +02:00
parent 3831b5f64f
commit 78ff318397
Signed by: 0x0ade
GPG key ID: E1960710FE4FBEEF
6 changed files with 107 additions and 33 deletions

View file

@ -79,12 +79,12 @@ public sealed class MainCmd : Cmd
return; return;
case "debugsizeold": case "debugsizeold":
Service.DebugConfig.SetSizeMode = SetSizeMode.LegacyHookSetWindowPos; Service.DebugConfig.ForceSizeMode = ForceSizeMode.LegacyRequestResolutionChange;
Service.PrintChat("Switched to legacy size mode. Please report your use case / any bugs with the new mode to 0x0ade."); Service.PrintChat("Switched to legacy size mode. Please report your use case / any bugs with the new mode to 0x0ade.");
return; return;
case "debugsizenew": case "debugsizenew":
Service.DebugConfig.SetSizeMode = SetSizeMode.InterceptSystemConfig; Service.DebugConfig.ForceSizeMode = ForceSizeMode.FakeWindowResize;
Service.PrintChat("Switched back to new size mode."); Service.PrintChat("Switched back to new size mode.");
return; return;
} }

View file

@ -8,13 +8,15 @@ public class DebugConfiguration
{ {
public bool IsDebug { get; set; } = false; public bool IsDebug { get; set; } = false;
public SetSizeMode SetSizeMode { get; set; } = SetSizeMode.InterceptSystemConfig; public SetWindowSizeMode SetWindowSizeMode { get; set; } = SetWindowSizeMode.InterceptSystemConfig;
public ForceSizeMode ForceSizeMode { get; set; } = ForceSizeMode.FakeWindowResize;
} }
public enum SetSizeMode public enum SetWindowSizeMode
{ {
/// <summary> /// <summary>
/// Intercept the system config width / height and scale it, but don't intercept window size sets. /// Intercept the system config width / height and scale it to the window size, and don't intercept window size sets.
/// Has got a mild risk of growing / shrinking windows if any codepath tries to get->set the window size, /// Has got a mild risk of growing / shrinking windows if any codepath tries to get->set the window size,
/// most notably with other plugins trying to change the window size. You shouldn't mix and match those anyway tho... /// most notably with other plugins trying to change the window size. You shouldn't mix and match those anyway tho...
/// ... and even then, I'm probably the only one who's going to read this and care about this. -jade /// ... and even then, I'm probably the only one who's going to read this and care about this. -jade
@ -22,8 +24,10 @@ public enum SetSizeMode
InterceptSystemConfig = 0, InterceptSystemConfig = 0,
/// <summary> /// <summary>
/// Legacy mode, went through more testing, works well except for the game getting confused about windowed mode size. /// Legacy mode, went through more initial testing, works well except for the game getting confused about windowed mode size.
/// Might revert or remove depending on how InterceptSystemConfig testing / fixups proceed. /// Might revert or remove depending on how InterceptSystemConfig testing / fixups proceed.
///
/// Hook SetWindowPos and turn the wanted size from scaled to window size on the fly.
/// </summary> /// </summary>
LegacyHookSetWindowPos = 1 LegacyHookSetWindowPos = 1
} }

View file

@ -62,13 +62,18 @@ public sealed unsafe class WindowRectHooks : IDisposable
return rv; return rv;
} }
public bool SetWindowPosOrig(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags)
{
return _setWindowPosHook.Original(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags);
}
private bool SetWindowPosDetour(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags) private bool SetWindowPosDetour(HWND hWnd, HWND hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags)
{ {
#if false #if false
Service.PluginLog.Debug($"SetWindowPosDetour A @ {X} {Y} {cx} {cy}"); Service.PluginLog.Debug($"SetWindowPosDetour A @ {X} {Y} {cx} {cy}");
#endif #endif
if (Service.DebugConfig.SetSizeMode == SetSizeMode.LegacyHookSetWindowPos && hWnd == Service.Plugin.CurrentHWND) if (Service.DebugConfig.SetWindowSizeMode == SetWindowSizeMode.LegacyHookSetWindowPos && hWnd == Service.Plugin.CurrentHWND)
{ {
Service.Plugin.ConvertCoordsGameToWin(ref cx, ref cy); Service.Plugin.ConvertCoordsGameToWin(ref cx, ref cy);
} }

View file

@ -74,32 +74,32 @@ public sealed unsafe class WndProcHook : IDisposable
} }
} }
private static void ParamToCoords(LPARAM param, out int x, out int y) public static void ParamToCoords(LPARAM param, out int x, out int y)
{ {
x = (short) (ushort) (param.Value & 0xFFFF); x = (short) (ushort) (param.Value & 0xFFFF);
y = (short) (ushort) (param.Value >> 16 & 0xFFFF); y = (short) (ushort) ((param.Value >> 16) & 0xFFFF);
} }
private static LPARAM CoordsToParam(int x, int y) public static LPARAM CoordsToParam(int x, int y)
{ {
nint value = 0; nint value = 0;
value |= ((ushort) (short) x) & 0xFFFF; value |= ((ushort) (short) x) & 0xFFFF;
value |= ((ushort) (short) y) >> 16 & 0xFFFF; value |= (((ushort) (short) y) & 0xFFFF) << 16;
return value; return value;
} }
private static void ParamToSize(LPARAM param, out uint x, out uint y) public static void ParamToSize(LPARAM param, out uint x, out uint y)
{ {
x = (ushort) (param.Value & 0xFFFF); x = (ushort) (param.Value & 0xFFFF);
y = (ushort) (param.Value >> 16 & 0xFFFF); y = (ushort) ((param.Value >> 16) & 0xFFFF);
} }
private static LPARAM SizeToParam(uint x, uint y) public static LPARAM SizeToParam(uint x, uint y)
{ {
nint value = 0; nint value = 0;
value |= ((ushort) x) & 0xFFFF; value |= ((ushort) x) & 0xFFFF;
value |= ((ushort) y) >> 16 & 0xFFFF; value |= (((ushort) y) & 0xFFFF) << 16;
return value; return value;
} }

View file

@ -1,4 +1,5 @@
using Dalamud.Game.ClientState.Keys; using CustomResolution.Hooks;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Game.Config; using Dalamud.Game.Config;
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
@ -29,6 +30,8 @@ public sealed unsafe class Plugin : IDalamudPlugin
private RECT _currentClientRect; private RECT _currentClientRect;
private DXVKDWMHackMode _currentDXVKDWMHackMode = DXVKDWMHackMode.Off; private DXVKDWMHackMode _currentDXVKDWMHackMode = DXVKDWMHackMode.Off;
private bool _ignoreConfigChanges = false; private bool _ignoreConfigChanges = false;
private bool _currentlyFakeResize = false;
private bool _requestedResolutionChange = false;
public Plugin(IDalamudPluginInterface pluginInterface) public Plugin(IDalamudPluginInterface pluginInterface)
{ {
@ -226,14 +229,9 @@ public sealed unsafe class Plugin : IDalamudPlugin
return; return;
} }
uint width, height;
var enabled = !_unloading && Service.Config.IsEnabled; var enabled = !_unloading && Service.Config.IsEnabled;
if (_wasEnabled != enabled)
{ uint width, height;
Service.PluginLog.Info($"Changing state to: {enabled}");
_wasEnabled = enabled;
}
if (Service.Config.IsScale || !enabled) if (Service.Config.IsScale || !enabled)
{ {
@ -258,15 +256,61 @@ public sealed unsafe class Plugin : IDalamudPlugin
height = 256; height = 256;
} }
if (width != dev->Width || height != dev->Height) _requestedResolutionChange |= (*_dev_RequestResolutionChange) != 0;
if (!_currentlyFakeResize && (_unloading || enabled || _wasEnabled || _requestedResolutionChange) &&
(width != dev->Width || height != dev->Height))
{ {
Service.PluginLog.Info($"Changing graphics resolution from {dev->Width} x {dev->Height} to {width} x {height}"); Service.PluginLog.Info($"Changing graphics resolution from {dev->Width} x {dev->Height} to {width} x {height}");
var mode = Service.DebugConfig.ForceSizeMode;
if (_requestedResolutionChange)
{
// Let's try to be cautious about other plugins (f.e. SimpleTweaks) changing the game resolution.
Service.PluginLog.Info($"Game resolution was changed externally - forcing resize via device, not window resize.");
mode = ForceSizeMode.LegacyRequestResolutionChange;
_requestedResolutionChange = false;
}
switch (mode)
{
case ForceSizeMode.Skip:
break;
case ForceSizeMode.LegacyRequestResolutionChange:
*_dev_NewWidth = width; *_dev_NewWidth = width;
*_dev_NewHeight = height; *_dev_NewHeight = height;
*_dev_RequestResolutionChange = 1; *_dev_RequestResolutionChange = 1;
Service.PluginLog.Info($"Changing game window from {win->WindowWidth} x {win->WindowHeight} to {width} x {height}"); Service.PluginLog.Info($"Changing game window from {win->WindowWidth} x {win->WindowHeight} to {width} x {height}");
win->WindowWidth = (int) width; win->WindowWidth = (int) width;
win->WindowHeight = (int) height; win->WindowHeight = (int) height;
break;
case ForceSizeMode.FakeWindowResize:
var adjustedClientRect = new RECT(0, 0, rectWidth, rectHeight);
AdjustWindowRect(&adjustedClientRect, (uint) GetWindowLongPtr(_currentHwnd, GWL.GWL_STYLE), false);
var adjustedWidth = adjustedClientRect.right - adjustedClientRect.left;
var adjustedHeight = adjustedClientRect.bottom - adjustedClientRect.top;
Service.PluginLog.Info($"Resizing window to {adjustedWidth} x {adjustedHeight}");
try
{
_currentlyFakeResize = true;
SendMessage(_currentHwnd, WM.WM_ENTERSIZEMOVE, 0, 0);
SendMessage(_currentHwnd, WM.WM_SIZE, SIZE_MAXSHOW, WndProcHook.SizeToParam((uint) adjustedWidth, (uint) adjustedHeight));
SendMessage(_currentHwnd, WM.WM_PAINT, 0, 0);
SendMessage(_currentHwnd, WM.WM_EXITSIZEMOVE, 0, 0);
}
finally
{
_currentlyFakeResize = false;
}
break;
default:
Service.PluginLog.Error($"Unknown ForceSizeMode: {Service.DebugConfig.ForceSizeMode}");
break;
}
}
if (_wasEnabled != enabled)
{
Service.PluginLog.Info($"Changed state to: {enabled}");
_wasEnabled = enabled;
} }
//Service.PluginLog.Debug($"NewWidth 0x{(long) (IntPtr) (&dev->NewWidth):X16}"); //Service.PluginLog.Debug($"NewWidth 0x{(long) (IntPtr) (&dev->NewWidth):X16}");
@ -423,7 +467,7 @@ public sealed unsafe class Plugin : IDalamudPlugin
{ {
case SystemConfigOption.ScreenWidth: case SystemConfigOption.ScreenWidth:
case SystemConfigOption.ScreenHeight: case SystemConfigOption.ScreenHeight:
if (Service.DebugConfig.SetSizeMode == SetSizeMode.InterceptSystemConfig) if (Service.DebugConfig.SetWindowSizeMode == SetWindowSizeMode.InterceptSystemConfig)
{ {
var name = e.ConfigOption.ToString(); var name = e.ConfigOption.ToString();
var valueOrig = Service.GameConfig.System.GetUInt(name); var valueOrig = Service.GameConfig.System.GetUInt(name);
@ -448,3 +492,22 @@ public sealed unsafe class Plugin : IDalamudPlugin
} }
} }
} }
public enum ForceSizeMode
{
Skip = -1,
/// <summary>
/// Fake a window resize event.
/// </summary>
FakeWindowResize = 0,
/// <summary>
/// Legacy mode, went through more initial testing, works well except for conflicts with other plugins.
/// Might revert or remove depending on how FakeWindowResize testing / fixups proceed.
///
/// Update the graphics device width / height and set RequestResolutionChange.
/// This is the same method that other plugins such as SimpleTweaks or XIVWindowResizer use.
/// </summary>
LegacyRequestResolutionChange = 1
}

View file

@ -33,6 +33,8 @@ time than I have on my hands right now.
</details> </details>
<details><summary>I'm using DLSS, and my game looks pixelated / is small!</summary> <details><summary>I'm using DLSS, and my game looks pixelated / is small!</summary>
DLSS and cres at very small scales (width / height under about 500 pixels) seems to be a conflicting combo. DLSS in FFXIV is bugged. No, I'm not joking: even without any plugins or mods loaded, it can glitch out when
Resizing the game window usually undoes any miniaturization, but I've yet to figure out why the game pixelates. Sorry! simply resizing the window (most notably by rapidly pressing WinKey + Down and WinKey + Up).
This issue doesn't happen with FSR and non-DLSS dynamic resolution.
</details> </details>