-
Notifications
You must be signed in to change notification settings - Fork 271
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1973 from Soreepeong/reshade-addon
add back DXGISwapChain::on_present hook as default for now
- Loading branch information
Showing
9 changed files
with
399 additions
and
188 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,141 @@ | ||
using System.Diagnostics; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
|
||
using Dalamud.Utility; | ||
|
||
using TerraFX.Interop.DirectX; | ||
using TerraFX.Interop.Windows; | ||
|
||
namespace Dalamud.Interface.Internal; | ||
|
||
/// <summary> | ||
/// This class manages interaction with the ImGui interface. | ||
/// </summary> | ||
internal partial class InterfaceManager | ||
internal unsafe partial class InterfaceManager | ||
{ | ||
private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags) | ||
// NOTE: Do not use HRESULT as return value type. It appears that .NET marshaller thinks HRESULT needs to be still | ||
// treated as a type that does not fit into RAX. | ||
|
||
/// <summary>Delegate for <c>DXGISwapChain::on_present(UINT flags, const DXGI_PRESENT_PARAMETERS *params)</c> in | ||
/// <c>dxgi_swapchain.cpp</c>.</summary> | ||
/// <param name="swapChain">Pointer to an instance of <c>DXGISwapChain</c>, which happens to be an | ||
/// <see cref="IDXGISwapChain"/>.</param> | ||
/// <param name="flags">An integer value that contains swap-chain presentation options. These options are defined by | ||
/// the <c>DXGI_PRESENT</c> constants.</param> | ||
/// <param name="presentParams">Optional; DXGI present parameters.</param> | ||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | ||
private delegate void ReShadeDxgiSwapChainPresentDelegate( | ||
ReShadeDxgiSwapChain* swapChain, | ||
uint flags, | ||
DXGI_PRESENT_PARAMETERS* presentParams); | ||
|
||
/// <summary>Delegate for <see cref="IDXGISwapChain.Present"/>. | ||
/// <a href="https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-present">Microsoft | ||
/// Learn</a>.</summary> | ||
/// <param name="swapChain">Pointer to an instance of <see cref="IDXGISwapChain"/>.</param> | ||
/// <param name="syncInterval">An integer that specifies how to synchronize presentation of a frame with the | ||
/// vertical blank.</param> | ||
/// <param name="flags">An integer value that contains swap-chain presentation options. These options are defined by | ||
/// the <c>DXGI_PRESENT</c> constants.</param> | ||
/// <returns>A <see cref="HRESULT"/> representing the result of the operation.</returns> | ||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | ||
private delegate int DxgiSwapChainPresentDelegate(IDXGISwapChain* swapChain, uint syncInterval, uint flags); | ||
|
||
/// <summary>Detour function for <see cref="IDXGISwapChain.ResizeBuffers"/>. | ||
/// <a href="https://learn.microsoft.com/en-us/windows/win32/api/dxgi/nf-dxgi-idxgiswapchain-resizebuffers"> | ||
/// Microsoft Learn</a>.</summary> | ||
/// <param name="swapChain">Pointer to an instance of <see cref="IDXGISwapChain"/>.</param> | ||
/// <param name="bufferCount">The number of buffers in the swap chain (including all back and front buffers). | ||
/// This number can be different from the number of buffers with which you created the swap chain. This number | ||
/// can't be greater than <see cref="DXGI.DXGI_MAX_SWAP_CHAIN_BUFFERS"/>. Set this number to zero to preserve the | ||
/// existing number of buffers in the swap chain. You can't specify less than two buffers for the flip presentation | ||
/// model.</param> | ||
/// <param name="width">The new width of the back buffer. If you specify zero, DXGI will use the width of the client | ||
/// area of the target window. You can't specify the width as zero if you called the | ||
/// <see cref="IDXGIFactory2.CreateSwapChainForComposition"/> method to create the swap chain for a composition | ||
/// surface.</param> | ||
/// <param name="height">The new height of the back buffer. If you specify zero, DXGI will use the height of the | ||
/// client area of the target window. You can't specify the height as zero if you called the | ||
/// <see cref="IDXGIFactory2.CreateSwapChainForComposition"/> method to create the swap chain for a composition | ||
/// surface.</param> | ||
/// <param name="newFormat">A DXGI_FORMAT-typed value for the new format of the back buffer. Set this value to | ||
/// <see cref="DXGI_FORMAT.DXGI_FORMAT_UNKNOWN"/> to preserve the existing format of the back buffer. The flip | ||
/// presentation model supports a more restricted set of formats than the bit-block transfer (bitblt) model.</param> | ||
/// <param name="swapChainFlags">A combination of <see cref="DXGI_SWAP_CHAIN_FLAG"/>-typed values that are combined | ||
/// by using a bitwise OR operation. The resulting value specifies options for swap-chain behavior.</param> | ||
/// <returns>A <see cref="HRESULT"/> representing the result of the operation.</returns> | ||
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] | ||
private delegate int ResizeBuffersDelegate( | ||
IDXGISwapChain* swapChain, | ||
uint bufferCount, | ||
uint width, | ||
uint height, | ||
DXGI_FORMAT newFormat, | ||
uint swapChainFlags); | ||
|
||
private void ReShadeDxgiSwapChainOnPresentDetour( | ||
ReShadeDxgiSwapChain* swapChain, | ||
uint flags, | ||
DXGI_PRESENT_PARAMETERS* presentParams) | ||
{ | ||
if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain)) | ||
return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags); | ||
|
||
Debug.Assert(this.dxgiPresentHook is not null, "How did PresentDetour get called when presentHook is null?"); | ||
Debug.Assert(this.dalamudAtlas is not null, "dalamudAtlas should have been set already"); | ||
|
||
if (this.scene == null) | ||
this.InitScene(swapChain); | ||
|
||
Debug.Assert(this.scene is not null, "InitScene did not set the scene field, but did not throw an exception."); | ||
Debug.Assert( | ||
this.reShadeDxgiSwapChainPresentHook is not null, | ||
"this.reShadeDxgiSwapChainPresentHook is not null"); | ||
|
||
if (!this.dalamudAtlas!.HasBuiltAtlas) | ||
{ | ||
if (this.dalamudAtlas.BuildTask.Exception != null) | ||
{ | ||
// TODO: Can we do something more user-friendly here? Unload instead? | ||
Log.Error(this.dalamudAtlas.BuildTask.Exception, "Failed to initialize Dalamud base fonts"); | ||
Util.Fatal("Failed to initialize Dalamud base fonts.\nPlease report this error.", "Dalamud"); | ||
} | ||
if (this.RenderDalamudCheckAndInitialize(swapChain->AsIDxgiSwapChain(), flags) is { } activeScene) | ||
this.RenderDalamudDraw(activeScene); | ||
|
||
return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags); | ||
} | ||
this.reShadeDxgiSwapChainPresentHook!.Original(swapChain, flags, presentParams); | ||
|
||
this.CumulativePresentCalls++; | ||
this.IsMainThreadInPresent = true; | ||
// Upstream call to system IDXGISwapChain::Present will be called by ReShade. | ||
} | ||
|
||
while (this.runBeforeImGuiRender.TryDequeue(out var action)) | ||
action.InvokeSafely(); | ||
private int DxgiSwapChainPresentDetour(IDXGISwapChain* swapChain, uint syncInterval, uint flags) | ||
{ | ||
Debug.Assert(this.dxgiSwapChainPresentHook is not null, "this.dxgiSwapChainPresentHook is not null"); | ||
|
||
RenderImGui(this.scene!); | ||
this.PostImGuiRender(); | ||
this.IsMainThreadInPresent = false; | ||
if (this.RenderDalamudCheckAndInitialize(swapChain, flags) is { } activeScene) | ||
this.RenderDalamudDraw(activeScene); | ||
|
||
return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags); | ||
return this.dxgiSwapChainPresentHook!.Original(swapChain, syncInterval, flags); | ||
} | ||
|
||
private IntPtr AsHookResizeBuffersDetour( | ||
IntPtr swapChain, uint bufferCount, uint width, uint height, uint newFormat, uint swapChainFlags) | ||
private int AsHookDxgiSwapChainResizeBuffersDetour( | ||
IDXGISwapChain* swapChain, | ||
uint bufferCount, | ||
uint width, | ||
uint height, | ||
DXGI_FORMAT newFormat, | ||
uint swapChainFlags) | ||
{ | ||
if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain)) | ||
return this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags); | ||
return this.dxgiSwapChainResizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags); | ||
|
||
#if DEBUG | ||
Log.Verbose( | ||
$"Calling resizebuffers swap@{swapChain.ToInt64():X}{bufferCount} {width} {height} {newFormat} {swapChainFlags}"); | ||
$"Calling resizebuffers swap@{(nint)swapChain:X}{bufferCount} {width} {height} {newFormat} {swapChainFlags}"); | ||
#endif | ||
|
||
this.ResizeBuffers?.InvokeSafely(); | ||
|
||
this.scene?.OnPreResize(); | ||
|
||
var ret = this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags); | ||
if (ret.ToInt64() == 0x887A0001) | ||
{ | ||
var ret = this.dxgiSwapChainResizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags); | ||
if (ret == DXGI.DXGI_ERROR_INVALID_CALL) | ||
Log.Error("invalid call to resizeBuffers"); | ||
} | ||
|
||
this.scene?.OnPostResize((int)width, (int)height); | ||
|
||
return ret; | ||
} | ||
|
||
/// <summary>Represents <c>DXGISwapChain</c> in ReShade.</summary> | ||
[StructLayout(LayoutKind.Sequential)] | ||
private struct ReShadeDxgiSwapChain | ||
{ | ||
// DXGISwapChain only implements IDXGISwapChain4. The only vtable should be that. | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
public IDXGISwapChain* AsIDxgiSwapChain() => (IDXGISwapChain*)Unsafe.AsPointer(ref this); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.