game: Update for 7.2hf3, move from sigs to callback slots
This commit is contained in:
parent
1b9d30af68
commit
796bc14bac
2 changed files with 79 additions and 23 deletions
|
@ -397,6 +397,11 @@ public unsafe struct DeviceEx
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public Device _;
|
public Device _;
|
||||||
|
|
||||||
|
[FieldOffset(0x40)]
|
||||||
|
public DeviceCallbacks* RenderTargetManagerResizeDestroyCallback;
|
||||||
|
[FieldOffset(0x48)]
|
||||||
|
public DeviceCallbacks* RenderTargetManagerResizeRegenCallback;
|
||||||
|
|
||||||
public ref byte RequestResolutionChange => ref _.RequestResolutionChange;
|
public ref byte RequestResolutionChange => ref _.RequestResolutionChange;
|
||||||
|
|
||||||
public ref byte RequestResolutionChangeUnk1 => ref RefPtr.For(ref _.RequestResolutionChange).Offs<byte>(0x1).Ref;
|
public ref byte RequestResolutionChangeUnk1 => ref RefPtr.For(ref _.RequestResolutionChange).Offs<byte>(0x1).Ref;
|
||||||
|
@ -419,7 +424,6 @@ public unsafe struct DeviceEx
|
||||||
public readonly ImmediateContextEx* ImmediateContext => (ImmediateContextEx*) _.ImmediateContext;
|
public readonly ImmediateContextEx* ImmediateContext => (ImmediateContextEx*) _.ImmediateContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ImmediateContextEx in FFXIVClientStructs is a bare minimum.
|
// ImmediateContextEx in FFXIVClientStructs is a bare minimum.
|
||||||
// https://github.com/aers/FFXIVClientStructs/blob/ef5e9a5997671fb2c9a72cb9d57d841855f62085/FFXIVClientStructs/FFXIV/Client/Graphics/Kernel/ImmediateContext.cs
|
// https://github.com/aers/FFXIVClientStructs/blob/ef5e9a5997671fb2c9a72cb9d57d841855f62085/FFXIVClientStructs/FFXIV/Client/Graphics/Kernel/ImmediateContext.cs
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
@ -431,3 +435,31 @@ public struct ImmediateContextEx
|
||||||
[FieldOffset(0x18)]
|
[FieldOffset(0x18)]
|
||||||
public nint IfNonZeroSkipPostTickProcess;
|
public nint IfNonZeroSkipPostTickProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct DeviceCallbacks
|
||||||
|
{
|
||||||
|
[FieldOffset(0x8)]
|
||||||
|
public CRITICAL_SECTION* Lock;
|
||||||
|
|
||||||
|
[FieldOffset(0x30)]
|
||||||
|
public DeviceCallbackSlot* Slots;
|
||||||
|
|
||||||
|
[FieldOffset(0x38)]
|
||||||
|
public uint MaxCount;
|
||||||
|
|
||||||
|
[FieldOffset(0x3c)]
|
||||||
|
public uint Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public unsafe struct DeviceCallbackSlot
|
||||||
|
{
|
||||||
|
[FieldOffset(0x0)]
|
||||||
|
public nint Function;
|
||||||
|
|
||||||
|
[FieldOffset(0x8)]
|
||||||
|
public nint Context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ using FloppyUtils;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using TerraFX.Interop.Windows;
|
||||||
|
|
||||||
namespace CustomResolution;
|
namespace CustomResolution;
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ public unsafe class GameSizeState : IDisposable
|
||||||
private Hook<RTMDestroyAfterResize> _rtmDestroyAfterResizeHook;
|
private Hook<RTMDestroyAfterResize> _rtmDestroyAfterResizeHook;
|
||||||
private Hook<RTMRegenAfterResize> _rtmRegenAfterResizeHook;
|
private Hook<RTMRegenAfterResize> _rtmRegenAfterResizeHook;
|
||||||
private Hook<ICDX11ProcessCommands> _icdx11ProcessCommandsHook;
|
private Hook<ICDX11ProcessCommands> _icdx11ProcessCommandsHook;
|
||||||
|
private Hook<DDX11PostTick> _ddx11PostTickHook;
|
||||||
|
|
||||||
private bool _wasEnabled = false;
|
private bool _wasEnabled = false;
|
||||||
private object _renderLock = new();
|
private object _renderLock = new();
|
||||||
|
@ -25,10 +27,7 @@ public unsafe class GameSizeState : IDisposable
|
||||||
public GameSizeState()
|
public GameSizeState()
|
||||||
{
|
{
|
||||||
/* Writes DynamicResolutionTargetHeight to size[1] near the end,
|
/* Writes DynamicResolutionTargetHeight to size[1] near the end,
|
||||||
* but only if in (gpose || main menu), only scale < 1??
|
* but if in (gpose || main menu), only scale < 1??
|
||||||
*
|
|
||||||
* RVAs:
|
|
||||||
* 7.2: 140470150
|
|
||||||
*/
|
*/
|
||||||
_rtmApplyScalingHook = Service.GameInteropProvider.HookFromAddress<RTMApplyScaling>(
|
_rtmApplyScalingHook = Service.GameInteropProvider.HookFromAddress<RTMApplyScaling>(
|
||||||
Service.SigScanner.ScanText("48 89 5C 24 18 55 56 57 41 56 41 57 48 83 EC 20 8B 42 04 0F 57 C0 48 8B"),
|
Service.SigScanner.ScanText("48 89 5C 24 18 55 56 57 41 56 41 57 48 83 EC 20 8B 42 04 0F 57 C0 48 8B"),
|
||||||
|
@ -36,10 +35,14 @@ public unsafe class GameSizeState : IDisposable
|
||||||
);
|
);
|
||||||
_rtmApplyScalingHook.Enable();
|
_rtmApplyScalingHook.Enable();
|
||||||
|
|
||||||
|
var dev = (DeviceEx*) Device.Instance();
|
||||||
|
|
||||||
/* Device.RequestResolutionChange and other triggers run some callbacks, namely
|
/* Device.RequestResolutionChange and other triggers run some callbacks, namely
|
||||||
* (at the time of 7.2) 0x40 for RTM destruction and 0x48 for RTM reconstruction,
|
* (at the time of 7.2) 0x40 for RTM destruction and 0x48 for RTM reconstruction,
|
||||||
* registered in RTM init and run in PostTick.
|
* registered in RTM init and run in PostTick.
|
||||||
*
|
*
|
||||||
|
* RenderTargetManager.Initialize calls subroutines to install those callbacks.
|
||||||
|
*
|
||||||
* We don't care about destruction as much because its behavior is unchanged, but
|
* We don't care about destruction as much because its behavior is unchanged, but
|
||||||
* we do want to call it instead of triggering a slow full game resize,
|
* we do want to call it instead of triggering a slow full game resize,
|
||||||
* which causes some annoyances with ReShade and possibly other external factors too.
|
* which causes some annoyances with ReShade and possibly other external factors too.
|
||||||
|
@ -49,12 +52,12 @@ public unsafe class GameSizeState : IDisposable
|
||||||
* and for being in the stack trace when dxgi updates the RT ptrs.
|
* and for being in the stack trace when dxgi updates the RT ptrs.
|
||||||
*/
|
*/
|
||||||
_rtmDestroyAfterResizeHook = Service.GameInteropProvider.HookFromAddress<RTMDestroyAfterResize>(
|
_rtmDestroyAfterResizeHook = Service.GameInteropProvider.HookFromAddress<RTMDestroyAfterResize>(
|
||||||
Service.SigScanner.ScanText("40 53 48 83 EC 20 48 8B 05 ?? ?? ?? ?? 48 8B D9 80 78 7A 00 ?? ?? ?? ?? ?? ?? 48 89 6C 24"),
|
dev->RenderTargetManagerResizeDestroyCallback->Slots[0].Function,
|
||||||
RTMDestroyAfterResizeDetour
|
RTMDestroyAfterResizeDetour
|
||||||
);
|
);
|
||||||
_rtmDestroyAfterResizeHook.Enable();
|
_rtmDestroyAfterResizeHook.Enable();
|
||||||
_rtmRegenAfterResizeHook = Service.GameInteropProvider.HookFromAddress<RTMRegenAfterResize>(
|
_rtmRegenAfterResizeHook = Service.GameInteropProvider.HookFromAddress<RTMRegenAfterResize>(
|
||||||
Service.SigScanner.ScanText("40 55 57 41 55 48 8D 6C 24 B9 48 81 EC A0 00 00 00 48 8B 05 50 10 2C 02 48 33 C4 48 89 45 27 4C"),
|
dev->RenderTargetManagerResizeRegenCallback->Slots[0].Function,
|
||||||
RTMRegenAfterResizeDetour
|
RTMRegenAfterResizeDetour
|
||||||
);
|
);
|
||||||
_rtmRegenAfterResizeHook.Enable();
|
_rtmRegenAfterResizeHook.Enable();
|
||||||
|
@ -70,6 +73,12 @@ public unsafe class GameSizeState : IDisposable
|
||||||
ICDX11ProcessCommandsDetour
|
ICDX11ProcessCommandsDetour
|
||||||
);
|
);
|
||||||
_icdx11ProcessCommandsHook.Enable();
|
_icdx11ProcessCommandsHook.Enable();
|
||||||
|
|
||||||
|
_ddx11PostTickHook = Service.GameInteropProvider.HookFromAddress<DDX11PostTick>(
|
||||||
|
Service.SigScanner.ScanText("48 89 5C 24 10 48 89 6C 24 18 48 89 74 24 20 57 41 54 41 55 41 56 41 57 B8 30 43 00 00 ?? ?? ?? ?? ?? 48 2B E0 48 8B 05 ?? ?? ?? ?? 48 33 C4 48 89 84 24 ?? ?? 00 00 8B 15"),
|
||||||
|
DDX11PostTickDetour
|
||||||
|
);
|
||||||
|
_ddx11PostTickHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ConfigDynRezo { get; private set; }
|
public bool ConfigDynRezo { get; private set; }
|
||||||
|
@ -85,10 +94,10 @@ public unsafe class GameSizeState : IDisposable
|
||||||
private delegate void RTMApplyScaling(RenderTargetManagerEx* rtm, uint* size, byte unk1);
|
private delegate void RTMApplyScaling(RenderTargetManagerEx* rtm, uint* size, byte unk1);
|
||||||
|
|
||||||
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
||||||
private delegate void RTMDestroyAfterResize(RenderTargetManagerEx* rtm);
|
private delegate byte RTMDestroyAfterResize();
|
||||||
|
|
||||||
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
||||||
private delegate void RTMRegenAfterResize(RenderTargetManagerEx* rtm);
|
private delegate void RTMRegenAfterResize();
|
||||||
|
|
||||||
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
// [UnmanagedFunctionPointer(CallingConvention.FastCall)]
|
||||||
private delegate void ICDX11ProcessCommands(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count);
|
private delegate void ICDX11ProcessCommands(ImmediateContext* ctx, RenderCommandBufferGroup* cmds, uint count);
|
||||||
|
@ -102,6 +111,7 @@ public unsafe class GameSizeState : IDisposable
|
||||||
_rtmDestroyAfterResizeHook.Dispose();
|
_rtmDestroyAfterResizeHook.Dispose();
|
||||||
_rtmRegenAfterResizeHook.Dispose();
|
_rtmRegenAfterResizeHook.Dispose();
|
||||||
_icdx11ProcessCommandsHook.Dispose();
|
_icdx11ProcessCommandsHook.Dispose();
|
||||||
|
_ddx11PostTickHook.Dispose();
|
||||||
Service.Framework.RunOnFrameworkThread(Update);
|
Service.Framework.RunOnFrameworkThread(Update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +135,7 @@ public unsafe class GameSizeState : IDisposable
|
||||||
_dbg.Append(@$"RTMApplyScaling 0x{(_rtmApplyScalingHook.IsDisposed ? null : _rtmApplyScalingHook.Address):X16}
|
_dbg.Append(@$"RTMApplyScaling 0x{(_rtmApplyScalingHook.IsDisposed ? null : _rtmApplyScalingHook.Address):X16}
|
||||||
RTMRegenAfterResize 0x{(_rtmRegenAfterResizeHook.IsDisposed ? null : _rtmRegenAfterResizeHook.Address):X16}
|
RTMRegenAfterResize 0x{(_rtmRegenAfterResizeHook.IsDisposed ? null : _rtmRegenAfterResizeHook.Address):X16}
|
||||||
ICDX11ProcessCommands 0x{(_icdx11ProcessCommandsHook.IsDisposed ? null : _icdx11ProcessCommandsHook.Address):X16}
|
ICDX11ProcessCommands 0x{(_icdx11ProcessCommandsHook.IsDisposed ? null : _icdx11ProcessCommandsHook.Address):X16}
|
||||||
DR !{gfx->DynamicRezoEnable} ?{gfx->DynamicRezoEnableBeyond1} _{gfx->DynamicRezoEnableCutScene} ?{gfx->DynamicRezoEnableUnkx47} ?{gfx->DynamicRezoEnableUnkx48}
|
DR !{gfx->DynamicRezoEnable} +{gfx->DynamicRezoEnableBeyond1} _{gfx->DynamicRezoEnableCutScene} ?{gfx->DynamicRezoEnableUnkx47} ?{gfx->DynamicRezoEnableUnkx48}
|
||||||
GR x{gfx->GraphicsRezoScale} ?{gfx->GraphicsRezoUnk1} _{gfx->GraphicsRezoUpscaleType} ?{gfx->GraphicsRezoUnk2}
|
GR x{gfx->GraphicsRezoScale} ?{gfx->GraphicsRezoUnk1} _{gfx->GraphicsRezoUpscaleType} ?{gfx->GraphicsRezoUnk2}
|
||||||
DEV 0x{(long) (nint) dev:X16}
|
DEV 0x{(long) (nint) dev:X16}
|
||||||
GFX 0x{(long) (nint) gfx:X16}
|
GFX 0x{(long) (nint) gfx:X16}
|
||||||
|
@ -170,8 +180,8 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
{
|
{
|
||||||
Service.PluginLog.Debug($"Regenerating dirty RTM - locking ImmediateContextDX11.ProcessCommands");
|
Service.PluginLog.Debug($"Regenerating dirty RTM - locking ImmediateContextDX11.ProcessCommands");
|
||||||
dev->RequestResolutionChange = 1;
|
dev->RequestResolutionChange = 1;
|
||||||
RTMDestroyAfterResizeDetour(rtm);
|
RTMDestroyAfterResizeDetour();
|
||||||
RTMRegenAfterResizeDetour(rtm);
|
RTMRegenAfterResizeDetour();
|
||||||
dev->RequestResolutionChange = 0;
|
dev->RequestResolutionChange = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,18 +197,24 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
{
|
{
|
||||||
// Can also be forced via dev->RequestResolutionChange, but while cleaner on paper, it trips up ReShade.
|
// Can also be forced via dev->RequestResolutionChange, but while cleaner on paper, it trips up ReShade.
|
||||||
Service.PluginLog.Debug("_forceUpdateRTM -> 1");
|
Service.PluginLog.Debug("_forceUpdateRTM -> 1");
|
||||||
_forceUpdateRTM = ForceUpdateRTMState._1_FakeHalf;
|
_forceUpdateRTM = ForceUpdateRTMState._1_FakeInv;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (enabled ? _forceUpdateRTM : ForceUpdateRTMState._0_Idle)
|
switch (enabled ? _forceUpdateRTM : ForceUpdateRTMState._0_Idle)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
|
if (_forceUpdateRTM < 0)
|
||||||
|
{
|
||||||
|
_forceUpdateRTM++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case ForceUpdateRTMState._0_Idle:
|
case ForceUpdateRTMState._0_Idle:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ForceUpdateRTMState._1_FakeHalf:
|
case ForceUpdateRTMState._1_FakeInv:
|
||||||
gfx->DynamicRezoEnable = 0;
|
gfx->DynamicRezoEnable = 0;
|
||||||
gfx->GraphicsRezoScale = 0.5f;
|
gfx->GraphicsRezoScale = MathF.Min(1f, 1f / scale);
|
||||||
Service.PluginLog.Debug("_forceUpdateRTM -> 2");
|
Service.PluginLog.Debug("_forceUpdateRTM -> 2");
|
||||||
_forceUpdateRTM = ForceUpdateRTMState._2_ToScale;
|
_forceUpdateRTM = ForceUpdateRTMState._2_ToScale;
|
||||||
break;
|
break;
|
||||||
|
@ -236,30 +252,33 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
gfx->DynamicRezoEnableBeyond1 = _DynamicRezoEnableBeyond1;
|
gfx->DynamicRezoEnableBeyond1 = _DynamicRezoEnableBeyond1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RTMDestroyAfterResizeDetour(RenderTargetManagerEx* rtm)
|
private byte RTMDestroyAfterResizeDetour()
|
||||||
{
|
{
|
||||||
ref var cfg = ref Service.Config._.Game;
|
ref var cfg = ref Service.Config._.Game;
|
||||||
if (Service.Plugin.Unloading || !cfg.IsEnabled)
|
if (Service.Plugin.Unloading || !cfg.IsEnabled)
|
||||||
{
|
{
|
||||||
_rtmDestroyAfterResizeHook.OriginalDisposeSafe(rtm);
|
return _rtmDestroyAfterResizeHook.OriginalDisposeSafe();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance();
|
||||||
|
|
||||||
Service.PluginLog.Debug($"Destroying RTM resources");
|
Service.PluginLog.Debug($"Destroying RTM resources");
|
||||||
_rtmDestroyAfterResizeHook.OriginalDisposeSafe(rtm);
|
byte rv = _rtmDestroyAfterResizeHook.OriginalDisposeSafe();
|
||||||
Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}");
|
Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}");
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RTMRegenAfterResizeDetour(RenderTargetManagerEx* rtm)
|
private void RTMRegenAfterResizeDetour()
|
||||||
{
|
{
|
||||||
ref var cfg = ref Service.Config._.Game;
|
ref var cfg = ref Service.Config._.Game;
|
||||||
if (Service.Plugin.Unloading || !cfg.IsEnabled)
|
if (Service.Plugin.Unloading || !cfg.IsEnabled)
|
||||||
{
|
{
|
||||||
_rtmRegenAfterResizeHook.OriginalDisposeSafe(rtm);
|
_rtmRegenAfterResizeHook.OriginalDisposeSafe();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var dev = (DeviceEx*) Device.Instance();
|
var dev = (DeviceEx*) Device.Instance();
|
||||||
|
var rtm = (RenderTargetManagerEx*) RenderTargetManager.Instance();
|
||||||
|
|
||||||
var _Width = dev->Width;
|
var _Width = dev->Width;
|
||||||
var _Height = dev->Height;
|
var _Height = dev->Height;
|
||||||
|
@ -268,7 +287,7 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
GetScaledWidthHeight(_Width, _Height, scale, out dev->Width, out dev->Height);
|
GetScaledWidthHeight(_Width, _Height, scale, out dev->Width, out dev->Height);
|
||||||
|
|
||||||
Service.PluginLog.Debug($"Regenerating RTM resources: {dev->Width} x {dev->Height}");
|
Service.PluginLog.Debug($"Regenerating RTM resources: {dev->Width} x {dev->Height}");
|
||||||
_rtmRegenAfterResizeHook.OriginalDisposeSafe(rtm);
|
_rtmRegenAfterResizeHook.OriginalDisposeSafe();
|
||||||
Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}");
|
Service.PluginLog.Debug($"After: 0x{(long) (nint) rtm->_.Unk20[0].Value->D3D11Texture2D:X16}");
|
||||||
|
|
||||||
dev->Width = _Width;
|
dev->Width = _Width;
|
||||||
|
@ -283,6 +302,11 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DDX11PostTickDetour(DeviceEx* dev)
|
||||||
|
{
|
||||||
|
_ddx11PostTickHook.OriginalDisposeSafe(dev);
|
||||||
|
}
|
||||||
|
|
||||||
private void GetScaledWidthHeight(uint width, uint height, float scale, out uint widthS, out uint heightS)
|
private void GetScaledWidthHeight(uint width, uint height, float scale, out uint widthS, out uint heightS)
|
||||||
{
|
{
|
||||||
heightS = (uint) MathF.Round(height * scale);
|
heightS = (uint) MathF.Round(height * scale);
|
||||||
|
@ -292,7 +316,7 @@ RR {dev->RequestRender} 0x{(long) dev->ImmediateContext->IfNonZeroSkipPostTickPr
|
||||||
private enum ForceUpdateRTMState
|
private enum ForceUpdateRTMState
|
||||||
{
|
{
|
||||||
_0_Idle,
|
_0_Idle,
|
||||||
_1_FakeHalf,
|
_1_FakeInv,
|
||||||
_2_ToScale
|
_2_ToScale
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue