diff --git a/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs b/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs index 02ab2b59cb..7343a7337e 100644 --- a/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs +++ b/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs @@ -1,10 +1,10 @@ -using System.Collections.Generic; -using System.Diagnostics; -using System.Runtime.InteropServices; - using Dalamud.Game.Internal.DXGI.Definitions; +using Dalamud.ImGuiScene.Helpers; + using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel; -using Serilog; + +using TerraFX.Interop.DirectX; +using TerraFX.Interop.Windows; namespace Dalamud.Game.Internal.DXGI; @@ -22,25 +22,18 @@ internal class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressR /// public IntPtr ResizeBuffers { get; set; } - /// - /// Gets a value indicating whether or not ReShade is loaded/used. - /// - public bool IsReshade { get; private set; } - /// protected override unsafe void Setup64Bit(ISigScanner sig) { - Device* kernelDev; - SwapChain* swapChain; void* dxgiSwapChain; while (true) { - kernelDev = Device.Instance(); + var kernelDev = Device.Instance(); if (kernelDev == null) continue; - swapChain = kernelDev->SwapChain; + var swapChain = kernelDev->SwapChain; if (swapChain == null) continue; @@ -51,77 +44,10 @@ protected override unsafe void Setup64Bit(ISigScanner sig) break; } - var scVtbl = GetVTblAddresses(new IntPtr(dxgiSwapChain), Enum.GetValues(typeof(IDXGISwapChainVtbl)).Length); - - this.Present = scVtbl[(int)IDXGISwapChainVtbl.Present]; - - var modules = Process.GetCurrentProcess().Modules; - foreach (ProcessModule processModule in modules) - { - if (processModule.FileName != null && processModule.FileName.EndsWith("game\\dxgi.dll")) - { - var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName); - - if (fileInfo.FileDescription == null) - break; - - if (!fileInfo.FileDescription.Contains("GShade") && !fileInfo.FileDescription.Contains("ReShade")) - break; - - // reshade master@4232872 RVA - // var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present - // var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present - - // DXGISwapChain::handle_device_loss => DXGISwapChain::Present => DXGISwapChain::runtime_present - - var scanner = new SigScanner(processModule); - var runtimePresentSig = "F6 C2 01 0F 85 ?? ?? ?? ??"; - - try - { - // Looks like this sig only works for GShade 4 - if (fileInfo.FileDescription?.Contains("GShade 4.") == true) - { - Log.Verbose("Hooking present for GShade 4"); - runtimePresentSig = "E8 ?? ?? ?? ?? 45 0F B6 5E ??"; - } - } - catch (Exception ex) - { - Log.Error(ex, "Failed to get reshade version info - falling back to default DXGISwapChain::runtime_present signature"); - } - - try - { - var p = scanner.ScanText(runtimePresentSig); - Log.Information($"ReShade DLL: {processModule.FileName} with DXGISwapChain::runtime_present at {p:X}"); - - this.Present = p; - this.IsReshade = true; - break; - } - catch (Exception ex) - { - Log.Error(ex, "Could not find reshade DXGISwapChain::runtime_present offset!"); - } - } - } - - this.ResizeBuffers = scVtbl[(int)IDXGISwapChainVtbl.ResizeBuffers]; - } - - private static List GetVTblAddresses(IntPtr pointer, int numberOfMethods) - { - return GetVTblAddresses(pointer, 0, numberOfMethods); - } - - private static List GetVTblAddresses(IntPtr pointer, int startIndex, int numberOfMethods) - { - var vtblAddresses = new List(); - var vTable = Marshal.ReadIntPtr(pointer); - for (var i = startIndex; i < startIndex + numberOfMethods; i++) - vtblAddresses.Add(Marshal.ReadIntPtr(vTable, i * IntPtr.Size)); // using IntPtr.Size allows us to support both 32 and 64-bit processes + using var sc = new ComPtr((IDXGISwapChain*)dxgiSwapChain); + ReShadePeeler.PeelSwapChain(&sc); - return vtblAddresses; + this.Present = (nint)sc.Get()->lpVtbl[(int)IDXGISwapChainVtbl.Present]; + this.ResizeBuffers = (nint)sc.Get()->lpVtbl[(int)IDXGISwapChainVtbl.ResizeBuffers]; } } diff --git a/Dalamud/ImGuiScene/Helpers/ReShadePeeler.cs b/Dalamud/ImGuiScene/Helpers/ReShadePeeler.cs new file mode 100644 index 0000000000..86bc88d9ee --- /dev/null +++ b/Dalamud/ImGuiScene/Helpers/ReShadePeeler.cs @@ -0,0 +1,134 @@ +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; + +using TerraFX.Interop.DirectX; +using TerraFX.Interop.Windows; + +using static TerraFX.Interop.Windows.Windows; + +namespace Dalamud.ImGuiScene.Helpers; + +/// +/// Peels ReShade off stuff. +/// +[SuppressMessage( + "StyleCop.CSharp.LayoutRules", + "SA1519:Braces should not be omitted from multi-line child statement", + Justification = "Multiple fixed blocks")] +internal static unsafe class ReShadePeeler +{ + /// + /// Peels if it is wrapped by ReShade. + /// + /// [inout] The COM pointer to an instance of . + /// A COM type that is or extends . + /// true if peeled. + public static bool PeelSwapChain(ComPtr* comptr) + where T : unmanaged, IDXGISwapChain.Interface => + PeelIUnknown(comptr, 0x10); + + /// + /// Peels if it is wrapped by ReShade. + /// + /// [inout] The COM pointer to an instance of . + /// A COM type that is or extends . + /// true if peeled. + public static bool PeelD3D12Device(ComPtr* comptr) + where T : unmanaged, ID3D12Device.Interface => + PeelIUnknown(comptr, 0x10); + + /// + /// Peels if it is wrapped by ReShade. + /// + /// [inout] The COM pointer to an instance of . + /// A COM type that is or extends . + /// true if peeled. + public static bool PeelD3D12CommandQueue(ComPtr* comptr) + where T : unmanaged, ID3D12CommandQueue.Interface => + PeelIUnknown(comptr, 0x10); + + private static bool PeelIUnknown(ComPtr* comptr, nint offset) + where T : unmanaged, IUnknown.Interface + { + if (comptr->Get() == null || !IsReShadedComObject(comptr->Get())) + return false; + + var punk = new ComPtr(*(IUnknown**)((nint)comptr->Get() + offset)); + using var comptr2 = default(ComPtr); + if (punk.As(&comptr2).FAILED) + return false; + comptr2.Swap(comptr); + return true; + } + + private static bool BelongsInReShadeDll(nint ptr) + { + foreach (ProcessModule processModule in Process.GetCurrentProcess().Modules) + { + if (ptr < processModule.BaseAddress) + continue; + + var dosh = (IMAGE_DOS_HEADER*)processModule.BaseAddress; + var nth = (IMAGE_NT_HEADERS64*)(processModule.BaseAddress + dosh->e_lfanew); + if (ptr >= processModule.BaseAddress + nth->OptionalHeader.SizeOfImage) + continue; + + fixed (byte* pfn0 = "CreateDXGIFactory"u8) + fixed (byte* pfn1 = "D2D1CreateDevice"u8) + fixed (byte* pfn2 = "D3D10CreateDevice"u8) + fixed (byte* pfn3 = "D3D11CreateDevice"u8) + fixed (byte* pfn4 = "D3D12CreateDevice"u8) + fixed (byte* pfn5 = "glBegin"u8) + fixed (byte* pfn6 = "vkCreateDevice"u8) + { + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn0) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn1) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn2) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn3) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn4) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn5) == 0) + continue; + if (GetProcAddress((HMODULE)dosh, (sbyte*)pfn6) == 0) + continue; + } + + var fileInfo = FileVersionInfo.GetVersionInfo(processModule.FileName); + + if (fileInfo.FileDescription == null) + continue; + + if (!fileInfo.FileDescription.Contains("GShade") && !fileInfo.FileDescription.Contains("ReShade")) + continue; + + return true; + } + + return false; + } + + private static bool IsReShadedComObject(T* obj) + where T : unmanaged, IUnknown.Interface + { + var vtbl = (nint*)((IUnknown*)obj)->lpVtbl; + try + { + for (var i = 0; i < 3; i++) + { + if (!BelongsInReShadeDll(Marshal.ReadIntPtr((nint)(&vtbl[i])))) + return false; + } + + return true; + } + catch + { + return false; + } + } +} diff --git a/Dalamud/ImGuiScene/Implementations/Dx11Renderer.ViewportHandler.cs b/Dalamud/ImGuiScene/Implementations/Dx11Renderer.ViewportHandler.cs index 4d300f7e2a..3336a78e35 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx11Renderer.ViewportHandler.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx11Renderer.ViewportHandler.cs @@ -210,6 +210,12 @@ public static ViewportData CreateDComposition(Dx11Renderer renderer, HWND hWnd) null, swapChain1.GetAddressOf()).ThrowHr(); + if (ReShadePeeler.PeelSwapChain(&swapChain1)) + { + swapChain1.Get()->ResizeBuffers(sd1.BufferCount, sd1.Width, sd1.Height, sd1.Format, sd1.Flags) + .ThrowHr(); + } + using var dcTarget = default(ComPtr); renderer.dcompDevice.Get()->CreateTargetForHwnd(hWnd, BOOL.TRUE, dcTarget.GetAddressOf()); @@ -258,6 +264,17 @@ public static ViewportData Create(Dx11Renderer renderer, HWND hWnd) dxgiFactory.Get()->CreateSwapChain((IUnknown*)renderer.device.Get(), &desc, swapChain.GetAddressOf()) .ThrowHr(); + if (ReShadePeeler.PeelSwapChain(&swapChain)) + { + swapChain.Get()->ResizeBuffers( + desc.BufferCount, + desc.BufferDesc.Width, + desc.BufferDesc.Height, + desc.BufferDesc.Format, + desc.Flags) + .ThrowHr(); + } + return Create(renderer, swapChain, null, null); } diff --git a/Dalamud/ImGuiScene/Implementations/Dx11Win32Scene.cs b/Dalamud/ImGuiScene/Implementations/Dx11Win32Scene.cs index 552d1273b5..7d78c68d85 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx11Win32Scene.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx11Win32Scene.cs @@ -29,6 +29,7 @@ internal sealed unsafe class Dx11Win32Scene : IWin32Scene private readonly Win32InputHandler imguiInput; private readonly WicEasy wicEasy; + private ComPtr swapChainPossiblyWrapped; private ComPtr swapChain; private ComPtr device; private ComPtr deviceContext; @@ -45,8 +46,10 @@ public Dx11Win32Scene(IDXGISwapChain* swapChain) this.wicEasy = new(); try { - swapChain->AddRef(); - this.swapChain.Attach(swapChain); + this.swapChainPossiblyWrapped = new(swapChain); + this.swapChain = new(swapChain); + fixed (ComPtr* ppSwapChain = &this.swapChain) + ReShadePeeler.PeelSwapChain(ppSwapChain); fixed (Guid* guid = &IID.IID_ID3D11Device) fixed (ID3D11Device** pp = &this.device.GetPinnableReference()) @@ -232,7 +235,9 @@ public void SetTexturePipeline(IDalamudTextureWrap textureHandle, ITexturePipeli public bool IsImGuiCursor(nint cursorHandle) => this.imguiInput.IsImGuiCursor(cursorHandle); /// - public bool IsAttachedToPresentationTarget(nint targetHandle) => this.swapChain.Get() == (void*)targetHandle; + public bool IsAttachedToPresentationTarget(nint targetHandle) => + this.swapChain.Get() == (void*)targetHandle + || this.swapChainPossiblyWrapped.Get() == (void*)targetHandle; /// public bool IsMainViewportFullScreen() @@ -319,5 +324,6 @@ private void ReleaseUnmanagedResources() this.swapChain.Dispose(); this.deviceContext.Dispose(); this.device.Dispose(); + this.swapChainPossiblyWrapped.Dispose(); } } diff --git a/Dalamud/ImGuiScene/Implementations/Dx12OnDx11Win32Scene.cs b/Dalamud/ImGuiScene/Implementations/Dx12OnDx11Win32Scene.cs index 112ecf74af..62f7299706 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx12OnDx11Win32Scene.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx12OnDx11Win32Scene.cs @@ -13,8 +13,6 @@ using TerraFX.Interop.DirectX; using TerraFX.Interop.Windows; -using Win32 = TerraFX.Interop.Windows.Windows; - namespace Dalamud.ImGuiScene.Implementations; /// @@ -28,6 +26,7 @@ internal unsafe class Dx12OnDx11Win32Scene : IWin32Scene { private readonly Dx12Win32Scene scene12; private readonly ComPtr[] shaderResourceViewsD3D11; + private ComPtr swapChainPossiblyWrapped; private ComPtr swapChain; private ComPtr device11; private ComPtr deviceContext; @@ -46,8 +45,10 @@ public Dx12OnDx11Win32Scene(IDXGISwapChain* swapChain) { try { - swapChain->AddRef(); - this.swapChain.Attach(swapChain); + this.swapChainPossiblyWrapped = new(swapChain); + this.swapChain = new(swapChain); + fixed (ComPtr* ppSwapChain = &this.swapChain) + ReShadePeeler.PeelSwapChain(ppSwapChain); fixed (Guid* guid = &IID.IID_ID3D11Device1) fixed (ID3D11Device1** pp = &this.device11.GetPinnableReference()) @@ -235,7 +236,9 @@ public void OnPostResize(int newWidth, int newHeight) public bool IsImGuiCursor(nint cursorHandle) => this.scene12.IsImGuiCursor(cursorHandle); /// - public bool IsAttachedToPresentationTarget(nint targetHandle) => this.swapChain.Get() == (void*)targetHandle; + public bool IsAttachedToPresentationTarget(nint targetHandle) => + this.swapChain.Get() == (void*)targetHandle + || this.swapChainPossiblyWrapped.Get() == (void*)targetHandle; /// public bool IsMainViewportFullScreen() @@ -293,6 +296,7 @@ private void ReleaseUnmanagedResources() s.Reset(); this.device12.Reset(); this.drawsOneSquare.Dispose(); + this.swapChainPossiblyWrapped.Dispose(); } private struct DrawsOneSquare : IDisposable diff --git a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.Queues.cs b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.Queues.cs index b24720f27b..d2b127e638 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.Queues.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.Queues.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using System.Threading; +using Dalamud.ImGuiScene.Helpers; using Dalamud.Utility; using TerraFX.Interop.DirectX; @@ -133,6 +134,8 @@ public CommandQueueWrapper(ID3D12Device* device, ID3D12CommandQueue* queue, stri try { this.queue = new(queue); + fixed (ComPtr* ppQueue = &this.queue) + ReShadePeeler.PeelD3D12CommandQueue(ppQueue); fixed (void* pName = $"{debugName}:{nameof(this.queue)}") this.queue.Get()->SetName((ushort*)pName).ThrowHr(); diff --git a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.ViewportHandler.cs b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.ViewportHandler.cs index b8c4298725..4510cb7ca9 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.ViewportHandler.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.ViewportHandler.cs @@ -299,6 +299,12 @@ public static ViewportData CreateDComposition(Dx12Renderer renderer, HWND hWnd, null, swapChain1.GetAddressOf()).ThrowHr(); + if (ReShadePeeler.PeelSwapChain(&swapChain1)) + { + swapChain1.Get()->ResizeBuffers(sd1.BufferCount, sd1.Width, sd1.Height, sd1.Format, sd1.Flags) + .ThrowHr(); + } + using var dcTarget = default(ComPtr); renderer.dcompDevice.Get()->CreateTargetForHwnd(hWnd, BOOL.TRUE, dcTarget.GetAddressOf()); @@ -370,6 +376,13 @@ public static ViewportData Create( null, null, swapChainTmp.GetAddressOf()).ThrowHr(); + + if (ReShadePeeler.PeelSwapChain(&swapChainTmp)) + { + swapChainTmp.Get()->ResizeBuffers(sd1.BufferCount, sd1.Width, sd1.Height, sd1.Format, sd1.Flags) + .ThrowHr(); + } + swapChainTmp.Get()->QueryInterface(piidSwapChain3, (void**)swapChain3.GetAddressOf()).ThrowHr(); } diff --git a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.cs b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.cs index d4e917e7a9..5a8ba18786 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx12Renderer.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx12Renderer.cs @@ -63,15 +63,22 @@ public Dx12Renderer(IDXGISwapChain3* swapChain, ID3D12Device* device, ID3D12Comm if (commandQueue is null) throw new NullReferenceException($"{nameof(commandQueue)} cannot be null."); + using var mySwapChain = new ComPtr(swapChain); + using var myDevice = new ComPtr(device); + using var myCommandQueue = new ComPtr(commandQueue); + ReShadePeeler.PeelSwapChain(&mySwapChain); + ReShadePeeler.PeelD3D12Device(&myDevice); + ReShadePeeler.PeelD3D12CommandQueue(&myCommandQueue); + var io = ImGui.GetIO(); if (ImGui.GetIO().NativePtr->BackendRendererName is not null) throw new InvalidOperationException("ImGui backend renderer seems to be have been already attached."); DXGI_SWAP_CHAIN_DESC desc; - swapChain->GetDesc(&desc).ThrowHr(); + mySwapChain.Get()->GetDesc(&desc).ThrowHr(); this.NumBackBuffers = (int)desc.BufferCount; this.rtvFormat = desc.BufferDesc.Format; - this.device = new(device); + myDevice.Swap(ref this.device); io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset | ImGuiBackendFlags.RendererHasViewports; @@ -97,8 +104,14 @@ public Dx12Renderer(IDXGISwapChain3* swapChain, ID3D12Device* device, ID3D12Comm this.viewportHandler = new(this); } - - this.mainViewport = ViewportData.Create(this, swapChain, commandQueue, nameof(this.mainViewport), null, null); + + this.mainViewport = ViewportData.Create( + this, + mySwapChain, + myCommandQueue, + nameof(this.mainViewport), + null, + null); ImGui.GetPlatformIO().Viewports[0].RendererUserData = this.mainViewport.AsHandle(); this.textureManager = new(this.device); } @@ -133,13 +146,16 @@ public Dx12Renderer(ID3D12Device* device, DXGI_FORMAT rtvFormat, int numBackBuff if (height <= 0) throw new ArgumentOutOfRangeException(nameof(height), height, "Must be a positive number."); + using var myDevice = new ComPtr(device); + ReShadePeeler.PeelD3D12Device(&myDevice); + var io = ImGui.GetIO(); if (ImGui.GetIO().NativePtr->BackendRendererName is not null) throw new InvalidOperationException("ImGui backend renderer seems to be have been already attached."); this.NumBackBuffers = numBackBuffers; this.rtvFormat = rtvFormat; - this.device = new(device); + myDevice.Swap(ref this.device); io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset | ImGuiBackendFlags.RendererHasViewports; diff --git a/Dalamud/ImGuiScene/Implementations/Dx12Win32Scene.cs b/Dalamud/ImGuiScene/Implementations/Dx12Win32Scene.cs index 1567796515..319e95871d 100644 --- a/Dalamud/ImGuiScene/Implementations/Dx12Win32Scene.cs +++ b/Dalamud/ImGuiScene/Implementations/Dx12Win32Scene.cs @@ -30,6 +30,7 @@ internal sealed unsafe class Dx12Win32Scene : IWin32Scene private readonly Win32InputHandler imguiInput; private readonly WicEasy wicEasy; + private ComPtr swapChainPossiblyWrapped; private ComPtr swapChain; private ComPtr device; @@ -46,15 +47,17 @@ public Dx12Win32Scene(IDXGISwapChain3* swapChain, ID3D12CommandQueue* commandQue { if (device is null || swapChain is null) throw new NullReferenceException(); - + this.wicEasy = new(); try { - device->AddRef(); - this.device.Attach(device); - - swapChain->AddRef(); - this.swapChain.Attach(swapChain); + this.device = new(device); + this.swapChainPossiblyWrapped = new(swapChain); + this.swapChain = new(swapChain); + fixed (ComPtr* ppSwapChain = &this.swapChain) + ReShadePeeler.PeelSwapChain(ppSwapChain); + fixed (ComPtr* ppDevice = &this.device) + ReShadePeeler.PeelD3D12Device(ppDevice); var desc = default(DXGI_SWAP_CHAIN_DESC); swapChain->GetDesc(&desc).ThrowHr(); @@ -94,8 +97,9 @@ public Dx12Win32Scene(ID3D12Device* device, HWND hwnd, int targetWidth, int targ this.wicEasy = new(); try { - device->AddRef(); - this.device.Attach(device); + this.device = new(device); + fixed (ComPtr* ppDevice = &this.device) + ReShadePeeler.PeelD3D12Device(ppDevice); this.targetWidth = targetWidth; this.targetHeight = targetHeight; @@ -281,7 +285,9 @@ public void SetTexturePipeline(IDalamudTextureWrap textureHandle, ITexturePipeli public bool IsImGuiCursor(nint cursorHandle) => this.imguiInput.IsImGuiCursor(cursorHandle); /// - public bool IsAttachedToPresentationTarget(nint targetHandle) => this.swapChain.Get() == (void*)targetHandle; + public bool IsAttachedToPresentationTarget(nint targetHandle) => + this.swapChain.Get() == (void*)targetHandle + || this.swapChainPossiblyWrapped.Get() == (void*)targetHandle; /// public bool IsMainViewportFullScreen() @@ -374,5 +380,6 @@ private void ReleaseUnmanagedResources() this.swapChain.Dispose(); this.device.Dispose(); + this.swapChainPossiblyWrapped.Dispose(); } } diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index feadcd7da8..6b26ce198a 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -589,16 +589,6 @@ private unsafe HRESULT PresentDetour(IDXGISwapChain* swapChain, uint syncInterva if (!this.scene.IsAttachedToPresentationTarget((nint)swapChain)) return this.presentHook!.Original(swapChain, syncInterval, presentFlags); - if (this.address.IsReshade) - { - var pRes = this.presentHook.Original(swapChain, syncInterval, presentFlags); - - this.RenderImGui(); - this.DisposeTextures(); - - return pRes; - } - this.RenderImGui(); this.DisposeTextures();