Skip to content

Commit

Permalink
Rebase cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Soreepeong committed Jul 19, 2024
1 parent 427e5e7 commit a9fc59d
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 147 deletions.
29 changes: 27 additions & 2 deletions Dalamud/Interface/ImGuiBackend/Dx11Win32Backend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,8 @@ public void OnPostResize(int newWidth, int newHeight)

/// <inheritdoc/>
public bool IsAttachedToPresentationTarget(nint targetHandle) =>
this.swapChain.Get() == (void*)targetHandle
|| this.swapChainPossiblyWrapped.Get() == (void*)targetHandle;
AreIUnknownEqual(this.swapChain.Get(), (IUnknown*)targetHandle)
|| AreIUnknownEqual(this.swapChainPossiblyWrapped.Get(), (IUnknown*)targetHandle);

/// <inheritdoc/>
public bool IsMainViewportFullScreen()
Expand All @@ -204,6 +204,31 @@ public bool IsMainViewportFullScreen()
return fullscreen;
}

private static bool AreIUnknownEqual<T1, T2>(T1* punk1, T2* punk2)
where T1 : unmanaged, IUnknown.Interface
where T2 : unmanaged, IUnknown.Interface
{
// https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
// For any given COM object (also known as a COM component), a specific query for the IUnknown interface on any
// of the object's interfaces must always return the same pointer value.

if (punk1 is null || punk2 is null)
return false;

fixed (Guid* iid = &IID.IID_IUnknown)
{
using var u1 = default(ComPtr<IUnknown>);
if (punk1->QueryInterface(iid, (void**)u1.GetAddressOf()).FAILED)
return false;

using var u2 = default(ComPtr<IUnknown>);
if (punk2->QueryInterface(iid, (void**)u2.GetAddressOf()).FAILED)
return false;

return u1.Get() == u2.Get();
}
}

private void ReleaseUnmanagedResources()
{
if (this.device.IsEmpty())
Expand Down
5 changes: 2 additions & 3 deletions Dalamud/Interface/Internal/InterfaceManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,8 @@ private unsafe void ContinueConstruction(
// This will wait for scene on its own. We just wait for this.dalamudAtlas.BuildTask in this.InitScene.
_ = this.dalamudAtlas.BuildFontsAsync();

SwapChainHelper.BusyWaitForGameDeviceSwapChain();

try
{
if (Service<DalamudConfiguration>.Get().WindowIsImmersive)
Expand All @@ -797,9 +799,6 @@ private unsafe void ContinueConstruction(
0,
this.SetCursorDetour);

SwapChainHelper.BusyWaitForGameDeviceSwapChain();
SwapChainHelper.DetectReShade();

Log.Verbose("===== S W A P C H A I N =====");
this.resizeBuffersHook = Hook<ResizeBuffersDelegate>.FromAddress(
(nint)SwapChainHelper.GameDeviceSwapChainVtbl->ResizeBuffers,
Expand Down
142 changes: 0 additions & 142 deletions Dalamud/Interface/Internal/SwapChainHelper.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
using System.Diagnostics;
using System.Threading;

using Dalamud.Game;
using Dalamud.Utility;

using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;

using Serilog;

using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;

namespace Dalamud.Interface.Internal;

/// <summary>Helper for dealing with swap chains.</summary>
internal static unsafe class SwapChainHelper
{
/// <summary>
/// Gets the function pointer for ReShade's DXGISwapChain::on_present.
/// <a href="https://github.com/crosire/reshade/blob/59eeecd0c902129a168cd772a63c46c5254ff2c5/source/dxgi/dxgi_swapchain.hpp#L88">Source.</a>
/// </summary>
public static delegate* unmanaged<nint, uint, nint, void> ReshadeOnPresent { get; private set; }

/// <summary>Gets the game's active instance of IDXGISwapChain that is initialized.</summary>
/// <value>Address of the game's instance of IDXGISwapChain, or <c>null</c> if not available (yet.)</value>
public static IDXGISwapChain* GameDeviceSwapChain
Expand Down Expand Up @@ -55,139 +42,10 @@ public static IDXGISwapChain.Vtbl<IDXGISwapChain>* GameDeviceSwapChainVtbl
}
}

/// <inheritdoc cref="IsGameDeviceSwapChain{T}"/>
public static bool IsGameDeviceSwapChain(nint punk) => IsGameDeviceSwapChain((IUnknown*)punk);

/// <summary>Determines if the given instance of IUnknown is the game device's swap chain.</summary>
/// <param name="punk">Object to check.</param>
/// <typeparam name="T">Type of the object to check.</typeparam>
/// <returns><c>true</c> if the object is the game's swap chain.</returns>
public static bool IsGameDeviceSwapChain<T>(T* punk) where T : unmanaged, IUnknown.Interface
{
// https://learn.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(refiid_void)
// For any given COM object (also known as a COM component), a specific query for the IUnknown interface on any
// of the object's interfaces must always return the same pointer value.

var gdsc = GameDeviceSwapChain;
if (gdsc is null || punk is null)
return false;

fixed (Guid* iid = &IID.IID_IUnknown)
{
using var u1 = default(ComPtr<IUnknown>);
if (gdsc->QueryInterface(iid, (void**)u1.GetAddressOf()).FAILED)
return false;

using var u2 = default(ComPtr<IUnknown>);
if (punk->QueryInterface(iid, (void**)u2.GetAddressOf()).FAILED)
return false;

return u1.Get() == u2.Get();
}
}

/// <summary>Wait for the game to have finished initializing the IDXGISwapChain.</summary>
public static void BusyWaitForGameDeviceSwapChain()
{
while (GameDeviceSwapChain is null)
Thread.Yield();
}

/// <summary>Detects ReShade and populate <see cref="ReshadeOnPresent"/>.</summary>
public static void DetectReShade()
{
var modules = Process.GetCurrentProcess().Modules;
foreach (ProcessModule processModule in modules)
{
if (!processModule.FileName.EndsWith("game\\dxgi.dll", StringComparison.InvariantCultureIgnoreCase))
continue;

try
{
var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName);

if (fileInfo.FileDescription == null)
break;

if (!fileInfo.FileDescription.Contains("GShade") && !fileInfo.FileDescription.Contains("ReShade"))
break;

// warning: these comments may no longer be accurate.
// reshade master@4232872 RVA
// var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present
// var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present
// DXGISwapChain::handle_device_loss =>df DXGISwapChain::Present => DXGISwapChain::runtime_present
// 5.2+ - F6 C2 01 0F 85
// 6.0+ - F6 C2 01 0F 85 88

var scanner = new SigScanner(processModule);
var reShadeDxgiPresent = nint.Zero;

if (fileInfo.FileVersion?.StartsWith("6.") == true)
{
// No Addon
if (scanner.TryScanText("F6 C2 01 0F 85 A8", out reShadeDxgiPresent))
{
Log.Information("Hooking present for ReShade 6 No-Addon");
}

// Addon
else if (scanner.TryScanText("F6 C2 01 0F 85 88", out reShadeDxgiPresent))
{
Log.Information("Hooking present for ReShade 6 Addon");
}

// Fallback
else
{
Log.Error("Failed to get ReShade 6 DXGISwapChain::on_present offset!");
}
}

// Looks like this sig only works for GShade 4
if (reShadeDxgiPresent == nint.Zero && fileInfo.FileDescription?.Contains("GShade 4.") == true)
{
if (scanner.TryScanText("E8 ?? ?? ?? ?? 45 0F B6 5E ??", out reShadeDxgiPresent))
{
Log.Information("Hooking present for GShade 4");
}
else
{
Log.Error("Failed to find GShade 4 DXGISwapChain::on_present offset!");
}
}

if (reShadeDxgiPresent == nint.Zero)
{
if (scanner.TryScanText("F6 C2 01 0F 85", out reShadeDxgiPresent))
{
Log.Information("Hooking present for ReShade with fallback 5.X sig");
}
else
{
Log.Error("Failed to find ReShade DXGISwapChain::on_present offset with fallback sig!");
}
}

Log.Information(
"ReShade DLL: {FileName} ({Info} - {Version}) with DXGISwapChain::on_present at {Address}",
processModule.FileName,
fileInfo.FileDescription ?? "Unknown",
fileInfo.FileVersion ?? "Unknown",
Util.DescribeAddress(reShadeDxgiPresent));

if (reShadeDxgiPresent != nint.Zero)
{
ReshadeOnPresent = (delegate* unmanaged<nint, uint, nint, void>)reShadeDxgiPresent;
}

break;
}
catch (Exception e)
{
Log.Error(e, "Failed to get ReShade version info");
break;
}
}
}
}

0 comments on commit a9fc59d

Please sign in to comment.