diff --git a/Dalamud/Interface/Internal/InterfaceManager.AsHook.cs b/Dalamud/Interface/Internal/InterfaceManager.AsHook.cs
new file mode 100644
index 000000000..b2afb970f
--- /dev/null
+++ b/Dalamud/Interface/Internal/InterfaceManager.AsHook.cs
@@ -0,0 +1,75 @@
+using System.Diagnostics;
+
+using Dalamud.Utility;
+
+namespace Dalamud.Interface.Internal;
+
+///
+/// This class manages interaction with the ImGui interface.
+///
+internal partial class InterfaceManager
+{
+ private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
+ {
+ 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.");
+
+ 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");
+ }
+
+ return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags);
+ }
+
+ this.CumulativePresentCalls++;
+ this.IsMainThreadInPresent = true;
+
+ while (this.runBeforeImGuiRender.TryDequeue(out var action))
+ action.InvokeSafely();
+
+ RenderImGui(this.scene!);
+ this.PostImGuiRender();
+ this.IsMainThreadInPresent = false;
+
+ return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags);
+ }
+
+ private IntPtr AsHookResizeBuffersDetour(
+ IntPtr swapChain, uint bufferCount, uint width, uint height, uint newFormat, uint swapChainFlags)
+ {
+ if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain))
+ return this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags);
+
+#if DEBUG
+ Log.Verbose(
+ $"Calling resizebuffers swap@{swapChain.ToInt64():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)
+ {
+ Log.Error("invalid call to resizeBuffers");
+ }
+
+ this.scene?.OnPostResize((int)width, (int)height);
+
+ return ret;
+ }
+}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.AsReShadeAddon.cs b/Dalamud/Interface/Internal/InterfaceManager.AsReShadeAddon.cs
new file mode 100644
index 000000000..0f1eeb707
--- /dev/null
+++ b/Dalamud/Interface/Internal/InterfaceManager.AsReShadeAddon.cs
@@ -0,0 +1,86 @@
+using System.Diagnostics;
+
+using Dalamud.Utility;
+
+using TerraFX.Interop.DirectX;
+
+namespace Dalamud.Interface.Internal;
+
+///
+/// This class manages interaction with the ImGui interface.
+///
+internal partial class InterfaceManager
+{
+ private unsafe void ReShadeAddonInterfaceOnDestroySwapChain(ref ReShadeAddonInterface.ApiObject swapchain)
+ {
+ var swapChain = swapchain.GetNative();
+ if (this.scene?.SwapChain.NativePointer != (nint)swapChain)
+ return;
+
+ this.scene?.OnPreResize();
+ }
+
+ private unsafe void ReShadeAddonInterfaceOnInitSwapChain(ref ReShadeAddonInterface.ApiObject swapchain)
+ {
+ var swapChain = swapchain.GetNative();
+ if (this.scene?.SwapChain.NativePointer != (nint)swapChain)
+ return;
+
+ DXGI_SWAP_CHAIN_DESC desc;
+ if (swapChain->GetDesc(&desc).FAILED)
+ return;
+
+ this.scene?.OnPostResize((int)desc.BufferDesc.Width, (int)desc.BufferDesc.Height);
+ }
+
+ private void ReShadeAddonInterfaceOnReShadeOverlay(ref ReShadeAddonInterface.ApiObject runtime)
+ {
+ var swapChain = runtime.GetNative();
+
+ if (this.scene == null)
+ this.InitScene(swapChain);
+
+ if (this.scene?.SwapChain.NativePointer != swapChain)
+ return;
+
+ Debug.Assert(this.dalamudAtlas is not null, "this.dalamudAtlas 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");
+ }
+
+ return;
+ }
+
+ this.CumulativePresentCalls++;
+ this.IsMainThreadInPresent = true;
+
+ while (this.runBeforeImGuiRender.TryDequeue(out var action))
+ action.InvokeSafely();
+
+ RenderImGui(this.scene!);
+ this.PostImGuiRender();
+ this.IsMainThreadInPresent = false;
+ }
+
+ private nint AsReShadeAddonResizeBuffersDetour(
+ nint swapChain,
+ uint bufferCount,
+ uint width,
+ uint height,
+ uint newFormat,
+ uint swapChainFlags)
+ {
+ // Hooked vtbl instead of registering ReShade event. This check is correct.
+ if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain))
+ return this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags);
+
+ this.ResizeBuffers?.InvokeSafely();
+ return this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags);
+ }
+}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index cbbf63075..10d508d99 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -13,6 +13,7 @@ using Dalamud.Game;
using Dalamud.Game.ClientState.GamePad;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Hooking;
+using Dalamud.Hooking.Internal;
using Dalamud.Hooking.WndProcHook;
using Dalamud.Interface.ImGuiNotification.Internal;
using Dalamud.Interface.Internal.ManagedAsserts;
@@ -29,10 +30,11 @@ using ImGuiNET;
using ImGuiScene;
+using JetBrains.Annotations;
+
using PInvoke;
-using SharpDX;
-using SharpDX.DXGI;
+using TerraFX.Interop.Windows;
// general dev notes, here because it's easiest
@@ -52,7 +54,7 @@ namespace Dalamud.Interface.Internal;
/// This class manages interaction with the ImGui interface.
///
[ServiceManager.EarlyLoadedService]
-internal class InterfaceManager : IInternalDisposableService
+internal partial class InterfaceManager : IInternalDisposableService
{
///
/// The default font size, in points.
@@ -75,6 +77,11 @@ internal class InterfaceManager : IInternalDisposableService
[ServiceManager.ServiceDependency]
private readonly Framework framework = Service.Get();
+ // ReShadeAddonInterface requires hooks to be alive to unregister itself.
+ [ServiceManager.ServiceDependency]
+ [UsedImplicitly]
+ private readonly HookManager hookManager = Service.Get();
+
private readonly ConcurrentQueue runBeforeImGuiRender = new();
private readonly ConcurrentQueue runAfterImGuiRender = new();
@@ -82,8 +89,8 @@ internal class InterfaceManager : IInternalDisposableService
private Hook? setCursorHook;
private Hook? dxgiPresentHook;
- private Hook? reshadeOnPresentHook;
private Hook? resizeBuffersHook;
+ private ReShadeAddonInterface? reShadeAddonInterface;
private IFontAtlas? dalamudAtlas;
private ILockedImFont? defaultFontResourceLock;
@@ -101,9 +108,6 @@ internal class InterfaceManager : IInternalDisposableService
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr DxgiPresentDelegate(IntPtr swapChain, uint syncInterval, uint presentFlags);
- [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
- private delegate void ReshadeOnPresentDelegate(nint swapChain, uint flags, nint presentParams);
-
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate IntPtr ResizeBuffersDelegate(IntPtr swapChain, uint bufferCount, uint width, uint height, uint newFormat, uint swapChainFlags);
@@ -299,8 +303,8 @@ internal class InterfaceManager : IInternalDisposableService
this.wndProcHookManager.PreWndProc -= this.WndProcHookManagerOnPreWndProc;
Interlocked.Exchange(ref this.setCursorHook, null)?.Dispose();
Interlocked.Exchange(ref this.dxgiPresentHook, null)?.Dispose();
- Interlocked.Exchange(ref this.reshadeOnPresentHook, null)?.Dispose();
Interlocked.Exchange(ref this.resizeBuffersHook, null)?.Dispose();
+ Interlocked.Exchange(ref this.reShadeAddonInterface, null)?.Dispose();
}
}
@@ -431,11 +435,11 @@ internal class InterfaceManager : IInternalDisposableService
try
{
var dxgiDev = this.Device.QueryInterfaceOrNull();
- var dxgiAdapter = dxgiDev?.Adapter.QueryInterfaceOrNull();
+ var dxgiAdapter = dxgiDev?.Adapter.QueryInterfaceOrNull();
if (dxgiAdapter == null)
return null;
- var memInfo = dxgiAdapter.QueryVideoMemoryInfo(0, MemorySegmentGroup.Local);
+ var memInfo = dxgiAdapter.QueryVideoMemoryInfo(0, SharpDX.DXGI.MemorySegmentGroup.Local);
return (memInfo.CurrentUsage, memInfo.CurrentReservation);
}
catch
@@ -464,11 +468,11 @@ internal class InterfaceManager : IInternalDisposableService
if (this.GameWindowHandle == 0)
throw new InvalidOperationException("Game window is not yet ready.");
var value = enabled ? 1 : 0;
- ((Result)NativeFunctions.DwmSetWindowAttribute(
+ ((HRESULT)NativeFunctions.DwmSetWindowAttribute(
this.GameWindowHandle,
NativeFunctions.DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
ref value,
- sizeof(int))).CheckError();
+ sizeof(int))).ThrowOnError();
}
private static InterfaceManager WhenFontsReady()
@@ -632,86 +636,6 @@ internal class InterfaceManager : IInternalDisposableService
args.SuppressWithValue(r.Value);
}
- private void ReshadeOnPresentDetour(nint swapChain, uint flags, nint presentParams)
- {
- if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain))
- {
- this.reshadeOnPresentHook!.Original(swapChain, flags, presentParams);
- return;
- }
-
- Debug.Assert(this.reshadeOnPresentHook is not null, "this.reshadeOnPresentHook is not null");
- Debug.Assert(this.dalamudAtlas is not null, "this.dalamudAtlas is not null");
-
- 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.");
-
- 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");
- }
-
- this.reshadeOnPresentHook!.Original(swapChain, flags, presentParams);
- return;
- }
-
- this.CumulativePresentCalls++;
- this.IsMainThreadInPresent = true;
-
- while (this.runBeforeImGuiRender.TryDequeue(out var action))
- action.InvokeSafely();
-
- this.reshadeOnPresentHook!.Original(swapChain, flags, presentParams);
-
- RenderImGui(this.scene!);
- this.PostImGuiRender();
- this.IsMainThreadInPresent = false;
- }
-
- private IntPtr PresentDetour(IntPtr swapChain, uint syncInterval, uint presentFlags)
- {
- 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.");
-
- 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");
- }
-
- return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags);
- }
-
- this.CumulativePresentCalls++;
- this.IsMainThreadInPresent = true;
-
- while (this.runBeforeImGuiRender.TryDequeue(out var action))
- action.InvokeSafely();
-
- RenderImGui(this.scene!);
- this.PostImGuiRender();
- this.IsMainThreadInPresent = false;
-
- return this.dxgiPresentHook!.Original(swapChain, syncInterval, presentFlags);
- }
-
private void PostImGuiRender()
{
while (this.runAfterImGuiRender.TryDequeue(out var action))
@@ -799,10 +723,7 @@ internal class InterfaceManager : IInternalDisposableService
() =>
{
// Update the ImGui default font.
- unsafe
- {
- ImGui.GetIO().NativePtr->FontDefault = fontLocked.ImFont;
- }
+ ImGui.GetIO().NativePtr->FontDefault = fontLocked.ImFont;
// Update the reference to the resources of the default font.
this.defaultFontResourceLock?.Dispose();
@@ -818,7 +739,6 @@ internal class InterfaceManager : IInternalDisposableService
_ = this.dalamudAtlas.BuildFontsAsync();
SwapChainHelper.BusyWaitForGameDeviceSwapChain();
- SwapChainHelper.DetectReShade();
try
{
@@ -839,52 +759,36 @@ internal class InterfaceManager : IInternalDisposableService
this.SetCursorDetour);
Log.Verbose("===== S W A P C H A I N =====");
- this.resizeBuffersHook = Hook.FromAddress(
- (nint)SwapChainHelper.GameDeviceSwapChainVtbl->ResizeBuffers,
- this.ResizeBuffersDetour);
- Log.Verbose($"ResizeBuffers address {Util.DescribeAddress(this.resizeBuffersHook!.Address)}");
-
- if (SwapChainHelper.ReshadeOnPresent is null)
+ if (ReShadeAddonInterface.TryRegisterAddon(out this.reShadeAddonInterface))
{
- var addr = (nint)SwapChainHelper.GameDeviceSwapChainVtbl->Present;
- this.dxgiPresentHook = Hook.FromAddress(addr, this.PresentDetour);
- Log.Verbose($"ReShade::DXGISwapChain::on_present address {Util.DescribeAddress(addr)}");
+ this.resizeBuffersHook = Hook.FromAddress(
+ (nint)SwapChainHelper.GameDeviceSwapChainVtbl->ResizeBuffers,
+ this.AsReShadeAddonResizeBuffersDetour);
+ Log.Verbose($"ResizeBuffers address {Util.DescribeAddress(this.resizeBuffersHook!.Address)}");
+
+ Log.Verbose(
+ "Registered as a ReShade({name}: 0x{addr:X}) addon.",
+ ReShadeAddonInterface.ReShadeModule!.FileName,
+ ReShadeAddonInterface.ReShadeModule!.BaseAddress);
+ this.reShadeAddonInterface.InitSwapChain += this.ReShadeAddonInterfaceOnInitSwapChain;
+ this.reShadeAddonInterface.DestroySwapChain += this.ReShadeAddonInterfaceOnDestroySwapChain;
+ this.reShadeAddonInterface.ReShadeOverlay += this.ReShadeAddonInterfaceOnReShadeOverlay;
}
else
{
- var addr = (nint)SwapChainHelper.ReshadeOnPresent;
- this.reshadeOnPresentHook = Hook.FromAddress(addr, this.ReshadeOnPresentDetour);
+ this.resizeBuffersHook = Hook.FromAddress(
+ (nint)SwapChainHelper.GameDeviceSwapChainVtbl->ResizeBuffers,
+ this.AsHookResizeBuffersDetour);
+ Log.Verbose($"ResizeBuffers address {Util.DescribeAddress(this.resizeBuffersHook!.Address)}");
+
+ var addr = (nint)SwapChainHelper.GameDeviceSwapChainVtbl->Present;
+ this.dxgiPresentHook = Hook.FromAddress(addr, this.PresentDetour);
Log.Verbose($"IDXGISwapChain::Present address {Util.DescribeAddress(addr)}");
}
this.setCursorHook.Enable();
this.dxgiPresentHook?.Enable();
- this.reshadeOnPresentHook?.Enable();
- this.resizeBuffersHook.Enable();
- }
-
- private IntPtr ResizeBuffersDetour(IntPtr swapChain, uint bufferCount, uint width, uint height, uint newFormat, uint swapChainFlags)
- {
- if (!SwapChainHelper.IsGameDeviceSwapChain(swapChain))
- return this.resizeBuffersHook!.Original(swapChain, bufferCount, width, height, newFormat, swapChainFlags);
-
-#if DEBUG
- Log.Verbose($"Calling resizebuffers swap@{swapChain.ToInt64():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)
- {
- Log.Error("invalid call to resizeBuffers");
- }
-
- this.scene?.OnPostResize((int)width, (int)height);
-
- return ret;
+ this.resizeBuffersHook?.Enable();
}
private IntPtr SetCursorDetour(IntPtr hCursor)
diff --git a/Dalamud/Interface/Internal/ReShadeAddonInterface.AddonEvent.cs b/Dalamud/Interface/Internal/ReShadeAddonInterface.AddonEvent.cs
new file mode 100644
index 000000000..23f01875d
--- /dev/null
+++ b/Dalamud/Interface/Internal/ReShadeAddonInterface.AddonEvent.cs
@@ -0,0 +1,1706 @@
+namespace Dalamud.Interface.Internal;
+
+/// ReShade interface.
+internal sealed partial class ReShadeAddonInterface
+{
+ /// Supported events emitted by ReShade.
+ private enum AddonEvent : uint
+ {
+#pragma warning disable
+
+ ///
+ /// Called after successful device creation, from:
+ ///
+ /// - IDirect3D9::CreateDevice
+ /// - IDirect3D9Ex::CreateDeviceEx
+ /// - IDirect3DDevice9::Reset
+ /// - IDirect3DDevice9Ex::ResetEx
+ /// - D3D10CreateDevice
+ /// - D3D10CreateDevice1
+ /// - D3D10CreateDeviceAndSwapChain
+ /// - D3D10CreateDeviceAndSwapChain1
+ /// - D3D11CreateDevice
+ /// - D3D11CreateDeviceAndSwapChain
+ /// - D3D12CreateDevice
+ /// - glMakeCurrent
+ /// - vkCreateDevice
+ ///
+ /// Callback function signature: void (api::device *device)
+ ///
+ InitDevice,
+
+ ///
+ /// Called on device destruction, before:
+ ///
+ /// - IDirect3DDevice9::Reset
+ /// - IDirect3DDevice9Ex::ResetEx
+ /// - IDirect3DDevice9::Release
+ /// - ID3D10Device::Release
+ /// - ID3D11Device::Release
+ /// - ID3D12Device::Release
+ /// - wglDeleteContext
+ /// - vkDestroyDevice
+ ///
+ /// Callback function signature: void (api::device *device)
+ ///
+ DestroyDevice,
+
+ ///
+ /// Called after successful command list creation, from:
+ ///
+ /// - ID3D11Device::CreateDeferredContext
+ /// - ID3D11Device1::CreateDeferredContext1
+ /// - ID3D11Device2::CreateDeferredContext2
+ /// - ID3D11Device3::CreateDeferredContext3
+ /// - ID3D12Device::CreateCommandList
+ /// - ID3D12Device4::CreateCommandList1
+ /// - vkAllocateCommandBuffers
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list)
+ ///
+ ///
+ /// In case of D3D9, D3D10, D3D11 and OpenGL this is called during device initialization as well and behaves as if an implicit immediate command list was created.
+ ///
+ InitCommandList,
+
+ ///
+ /// Called on command list destruction, before:
+ ///
+ /// - ID3D11CommandList::Release
+ /// - ID3D12CommandList::Release
+ /// - vkFreeCommandBuffers
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list)
+ ///
+ DestroyCommandList,
+
+ ///
+ /// Called after successful command queue creation, from:
+ ///
+ /// - ID3D12Device::CreateCommandQueue
+ /// - vkCreateDevice (for every queue associated with the device)
+ ///
+ /// Callback function signature: void (api::command_queue *queue)
+ ///
+ ///
+ /// In case of D3D9, D3D10, D3D11 and OpenGL this is called during device initialization as well and behaves as if an implicit command queue was created.
+ ///
+ InitCommandQueue,
+
+ ///
+ /// Called on command queue destruction, before:
+ ///
+ /// - ID3D12CommandQueue::Release
+ /// - vkDestroyDevice (for every queue associated with the device)
+ ///
+ /// Callback function signature: void (api::command_queue *queue)
+ ///
+ DestroyCommandQueue,
+
+ ///
+ /// Called after successful swap chain creation, from:
+ ///
+ /// - IDirect3D9::CreateDevice (for the implicit swap chain)
+ /// - IDirect3D9Ex::CreateDeviceEx (for the implicit swap chain)
+ /// - IDirect3D9Device::CreateAdditionalSwapChain
+ /// - IDXGIFactory::CreateSwapChain
+ /// - IDXGIFactory2::CreateSwapChain(...)
+ /// - wglMakeCurrent
+ /// - wglSwapBuffers (after window was resized)
+ /// - vkCreateSwapchainKHR
+ /// - xrCreateSession
+ ///
+ /// In addition, called when swap chain is resized, after:
+ ///
+ /// - IDirect3DDevice9::Reset (for the implicit swap chain)
+ /// - IDirect3DDevice9Ex::ResetEx (for the implicit swap chain)
+ /// - IDXGISwapChain::ResizeBuffers
+ /// - IDXGISwapChain3::ResizeBuffers1
+ ///
+ /// Callback function signature: void (api::swapchain *swapchain)
+ ///
+ InitSwapChain,
+
+ ///
+ /// Called on swap chain creation, before:
+ ///
+ /// - IDirect3D9::CreateDevice (for the implicit swap chain)
+ /// - IDirect3D9Ex::CreateDeviceEx (for the implicit swap chain)
+ /// - IDirect3D9Device::CreateAdditionalSwapChain
+ /// - IDirect3D9Device::Reset (for the implicit swap chain)
+ /// - IDirect3D9DeviceEx::ResetEx (for the implicit swap chain)
+ /// - IDXGIFactory::CreateSwapChain
+ /// - IDXGIFactory2::CreateSwapChain(...)
+ /// - IDXGISwapChain::ResizeBuffers
+ /// - IDXGISwapChain3::ResizeBuffers1
+ /// - wglSetPixelFormat
+ /// - vkCreateSwapchainKHR
+ ///
+ /// Callback function signature: bool (api::swapchain_desc &desc, void *hwnd)
+ ///
+ ///
+ /// To overwrite the swap chain description, modify desc in the callback and return , otherwise return .
+ ///
+ CreateSwapChain,
+
+ ///
+ /// Called on swap chain destruction, before:
+ ///
+ /// - IDirect3DDevice9::Release (for the implicit swap chain)
+ /// - IDirect3DSwapChain9::Release
+ /// - IDXGISwapChain::Release
+ /// - wglDeleteContext
+ /// - wglSwapBuffers (after window was resized)
+ /// - vkDestroySwapchainKHR
+ /// - xrDestroySession
+ ///
+ /// In addition, called when swap chain is resized, before:
+ ///
+ /// - IDirect3DDevice9::Reset (for the implicit swap chain)
+ /// - IDirect3DDevice9Ex::ResetEx (for the implicit swap chain)
+ /// - IDXGISwapChain::ResizeBuffers
+ /// - IDXGISwapChain1::ResizeBuffers1
+ ///
+ /// Callback function signature: void (api::swapchain *swapchain)
+ ///
+ DestroySwapChain,
+
+ ///
+ /// Called after effect runtime initialization (which happens after swap chain creation or a swap chain buffer resize).
+ /// Callback function signature: void (api::effect_runtime *runtime)
+ ///
+ InitEffectRuntime,
+
+ ///
+ /// Called when an effect runtime is reset or destroyed.
+ /// Callback function signature: void (api::effect_runtime *runtime)
+ ///
+ DestroyEffectRuntime,
+
+ ///
+ /// Called after successful sampler creation from:
+ ///
+ /// - ID3D10Device::CreateSamplerState
+ /// - ID3D11Device::CreateSamplerState
+ /// - ID3D12Device::CreateSampler
+ /// - vkCreateSampler
+ ///
+ /// Callback function signature: void (api::device *device, const api::sampler_desc &desc, api::sampler sampler)
+ ///
+ ///
+ /// Is not called in D3D9 (since samplers are loose state there) or OpenGL.
+ ///
+ InitSampler,
+
+ ///
+ /// Called on sampler creation, before:
+ ///
+ /// - ID3D10Device::CreateSamplerState
+ /// - ID3D11Device::CreateSamplerState
+ /// - ID3D12Device::CreateSampler
+ /// - ID3D12Device::CreateRootSignature
+ /// - vkCreateSampler
+ ///
+ /// Callback function signature: bool (api::device *device, api::sampler_desc &desc)
+ ///
+ ///
+ /// To overwrite the sampler description, modify desc in the callback and return , otherwise return .
+ /// Is not called in D3D9 (since samplers are loose state there) or OpenGL.
+ ///
+ CreateSampler,
+
+ ///
+ /// Called on sampler destruction, before:
+ ///
+ /// - ID3D10SamplerState::Release
+ /// - ID3D11SamplerState::Release
+ /// - glDeleteSamplers
+ /// - vkDestroySampler
+ ///
+ /// Callback function signature: void (api::device *device, api::sampler sampler)
+ ///
+ ///
+ /// Is not called in D3D9 (since samplers are loose state there), D3D12 (since samplers are descriptor handles instead of objects there) or OpenGL.
+ ///
+ DestroySampler,
+
+ ///
+ /// Called after successful resource creation from:
+ ///
+ /// - IDirect3DDevice9::CreateVertexBuffer
+ /// - IDirect3DDevice9::CreateIndexBuffer
+ /// - IDirect3DDevice9::CreateTexture
+ /// - IDirect3DDevice9::CreateCubeTexture
+ /// - IDirect3DDevice9::CreateVolumeTexture
+ /// - IDirect3DDevice9::CreateRenderTargetSurface
+ /// - IDirect3DDevice9::CreateDepthStencilSurface
+ /// - IDirect3DDevice9::CreateOffscreenPlainSurface
+ /// - IDirect3DDevice9Ex::CreateRenderTargetSurfaceEx
+ /// - IDirect3DDevice9Ex::CreateDepthStencilSurfaceEx
+ /// - IDirect3DDevice9Ex::CreateOffscreenPlainSurfaceEx
+ /// - ID3D10Device::CreateBuffer
+ /// - ID3D10Device::CreateTexture1D
+ /// - ID3D10Device::CreateTexture2D
+ /// - ID3D10Device::CreateTexture2D
+ /// - ID3D11Device::CreateBuffer
+ /// - ID3D11Device::CreateTexture1D
+ /// - ID3D11Device::CreateTexture2D
+ /// - ID3D11Device::CreateTexture3D
+ /// - ID3D11Device3::CreateTexture2D
+ /// - ID3D11Device3::CreateTexture3D
+ /// - ID3D12Device::CreateCommittedResource
+ /// - ID3D12Device::CreatePlacedResource
+ /// - ID3D12Device::CreateReservedResource
+ /// - ID3D12Device4::CreateCommittedResource1
+ /// - ID3D12Device4::CreateReservedResource1
+ /// - glBufferData
+ /// - glBufferStorage
+ /// - glNamedBufferData
+ /// - glNamedBufferStorage
+ /// - glTexImage1D
+ /// - glTexImage2D
+ /// - glTexImage2DMultisample
+ /// - glTexImage3D
+ /// - glTexImage3DMultisample
+ /// - glCompressedTexImage1D
+ /// - glCompressedTexImage2D
+ /// - glCompressedTexImage3D
+ /// - glTexStorage1D
+ /// - glTexStorage2D
+ /// - glTexStorage2DMultisample
+ /// - glTexStorage3D
+ /// - glTexStorage3DMultisample
+ /// - glTextureStorage1D
+ /// - glTextureStorage2D
+ /// - glTextureStorage2DMultisample
+ /// - glTextureStorage3D
+ /// - glTextureStorage3DMultisample
+ /// - glRenderbufferStorage
+ /// - glRenderbufferStorageMultisample
+ /// - glNamedRenderbufferStorage
+ /// - glNamedRenderbufferStorageMultisample
+ /// - vkBindBufferMemory
+ /// - vkBindBufferMemory2
+ /// - vkBindImageMemory
+ /// - vkBindImageMemory2
+ ///
+ /// Callback function signature: void (api::device *device, const api::resource_desc &desc, const api::subresource_data *initial_data, api::resource_usage initial_state, api::resource resource)
+ ///
+ ///
+ /// May be called multiple times with the same resource handle (whenever the resource is updated or its reference count is incremented).
+ ///
+ InitResource,
+
+ ///
+ /// Called on resource creation, before:
+ ///
+ /// - IDirect3DDevice9::CreateVertexBuffer
+ /// - IDirect3DDevice9::CreateIndexBuffer
+ /// - IDirect3DDevice9::CreateTexture
+ /// - IDirect3DDevice9::CreateCubeTexture
+ /// - IDirect3DDevice9::CreateVolumeTexture
+ /// - IDirect3DDevice9::CreateRenderTargetSurface
+ /// - IDirect3DDevice9::CreateDepthStencilSurface
+ /// - IDirect3DDevice9::CreateOffscreenPlainSurface
+ /// - IDirect3DDevice9Ex::CreateRenderTargetSurfaceEx
+ /// - IDirect3DDevice9Ex::CreateDepthStencilSurfaceEx
+ /// - IDirect3DDevice9Ex::CreateOffscreenPlainSurfaceEx
+ /// - ID3D10Device::CreateBuffer
+ /// - ID3D10Device::CreateTexture1D
+ /// - ID3D10Device::CreateTexture2D
+ /// - ID3D10Device::CreateTexture2D
+ /// - ID3D11Device::CreateBuffer
+ /// - ID3D11Device::CreateTexture1D
+ /// - ID3D11Device::CreateTexture2D
+ /// - ID3D11Device::CreateTexture3D
+ /// - ID3D11Device3::CreateTexture2D
+ /// - ID3D11Device3::CreateTexture3D
+ /// - ID3D12Device::CreateCommittedResource
+ /// - ID3D12Device::CreatePlacedResource
+ /// - ID3D12Device::CreateReservedResource
+ /// - ID3D12Device4::CreateCommittedResource1
+ /// - ID3D12Device4::CreateReservedResource1
+ /// - glBufferData
+ /// - glBufferStorage
+ /// - glNamedBufferData
+ /// - glNamedBufferStorage
+ /// - glTexImage1D
+ /// - glTexImage2D
+ /// - glTexImage2DMultisample
+ /// - glTexImage3D
+ /// - glTexImage3DMultisample
+ /// - glCompressedTexImage1D
+ /// - glCompressedTexImage2D
+ /// - glCompressedTexImage3D
+ /// - glTexStorage1D
+ /// - glTexStorage2D
+ /// - glTexStorage2DMultisample
+ /// - glTexStorage3D
+ /// - glTexStorage3DMultisample
+ /// - glTextureStorage1D
+ /// - glTextureStorage2D
+ /// - glTextureStorage2DMultisample
+ /// - glTextureStorage3D
+ /// - glTextureStorage3DMultisample
+ /// - glRenderbufferStorage
+ /// - glRenderbufferStorageMultisample
+ /// - glNamedRenderbufferStorage
+ /// - glNamedRenderbufferStorageMultisample
+ /// - vkCreateBuffer
+ /// - vkCreateImage
+ ///
+ /// Callback function signature: bool (api::device *device, api::resource_desc &desc, api::subresource_data *initial_data, api::resource_usage initial_state)
+ ///
+ ///
+ /// To overwrite the resource description, modify desc in the callback and return , otherwise return .
+ ///
+ CreateResource,
+
+ ///
+ /// Called on resource destruction, before:
+ ///
+ /// - IDirect3DResource9::Release
+ /// - ID3D10Resource::Release
+ /// - ID3D11Resource::Release
+ /// - ID3D12Resource::Release
+ /// - glDeleteBuffers
+ /// - glDeleteTextures
+ /// - glDeleteRenderbuffers
+ /// - vkDestroyBuffer
+ /// - vkDestroyImage
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource)
+ ///
+ DestroyResource,
+
+ ///
+ /// Called after successful resource view creation from:
+ ///
+ /// - IDirect3DDevice9::CreateTexture
+ /// - IDirect3DDevice9::CreateCubeTexture
+ /// - IDirect3DDevice9::CreateVolumeTexture
+ /// - ID3D10Device::CreateShaderResourceView
+ /// - ID3D10Device::CreateRenderTargetView
+ /// - ID3D10Device::CreateDepthStencilView
+ /// - ID3D10Device1::CreateShaderResourceView1
+ /// - ID3D11Device::CreateShaderResourceView
+ /// - ID3D11Device::CreateUnorderedAccessView
+ /// - ID3D11Device::CreateRenderTargetView
+ /// - ID3D11Device::CreateDepthStencilView
+ /// - ID3D11Device3::CreateShaderResourceView1
+ /// - ID3D11Device3::CreateUnorderedAccessView1
+ /// - ID3D11Device3::CreateRenderTargetView1
+ /// - ID3D12Device::CreateShaderResourceView
+ /// - ID3D12Device::CreateUnorderedAccessView
+ /// - ID3D12Device::CreateRenderTargetView
+ /// - ID3D12Device::CreateDepthStencilView
+ /// - glTexBuffer
+ /// - glTextureBuffer
+ /// - glTextureView
+ /// - vkCreateBufferView
+ /// - vkCreateImageView
+ /// - vkCreateAccelerationStructureKHR
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource, api::resource_usage usage_type, const api::resource_view_desc &desc, api::resource_view view)
+ ///
+ ///
+ /// May be called multiple times with the same resource view handle (whenever the resource view is updated).
+ ///
+ InitResourceView,
+
+ ///
+ /// Called on resource view creation, before:
+ ///
+ /// - ID3D10Device::CreateShaderResourceView
+ /// - ID3D10Device::CreateRenderTargetView
+ /// - ID3D10Device::CreateDepthStencilView
+ /// - ID3D10Device1::CreateShaderResourceView1
+ /// - ID3D11Device::CreateShaderResourceView
+ /// - ID3D11Device::CreateUnorderedAccessView
+ /// - ID3D11Device::CreateRenderTargetView
+ /// - ID3D11Device::CreateDepthStencilView
+ /// - ID3D11Device3::CreateShaderResourceView1
+ /// - ID3D11Device3::CreateUnorderedAccessView1
+ /// - ID3D11Device3::CreateRenderTargetView1
+ /// - ID3D12Device::CreateShaderResourceView
+ /// - ID3D12Device::CreateUnorderedAccessView
+ /// - ID3D12Device::CreateRenderTargetView
+ /// - ID3D12Device::CreateDepthStencilView
+ /// - glTexBuffer
+ /// - glTextureBuffer
+ /// - glTextureView
+ /// - vkCreateBufferView
+ /// - vkCreateImageView
+ /// - vkCreateAccelerationStructureKHR
+ ///
+ /// Callback function signature: bool (api::device *device, api::resource resource, api::resource_usage usage_type, api::resource_view_desc &desc)
+ ///
+ ///
+ /// To overwrite the resource view description, modify desc in the callback and return , otherwise return .
+ /// Is not called in D3D9 (since resource views are tied to resources there).
+ ///
+ CreateResourceView,
+
+ ///
+ /// Called on resource view destruction, before:
+ ///
+ /// - IDirect3DResource9::Release
+ /// - ID3D10View::Release
+ /// - ID3D11View::Release
+ /// - glDeleteTextures
+ /// - vkDestroyBufferView
+ /// - vkDestroyImageView
+ /// - vkDestroyAccelerationStructureKHR
+ ///
+ /// Callback function signature: void (api::device *device, api::resource_view view)
+ ///
+ ///
+ /// Is not called in D3D12 (since resource views are descriptor handles instead of objects there).
+ ///
+ DestroyResourceView,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DVertexBuffer9::Lock
+ /// - IDirect3DIndexBuffer9::Lock
+ /// - ID3D10Resource::Map
+ /// - ID3D11DeviceContext::Map
+ /// - ID3D12Resource::Map
+ /// - glMapBuffer
+ /// - glMapBufferRange
+ /// - glMapNamedBuffer
+ /// - glMapNamedBufferRange
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource, uint64_t offset, uint64_t size, api::map_access access, void **data)
+ ///
+ MapBufferRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DVertexBuffer9::Unlock
+ /// - IDirect3DIndexBuffer9::Unlock
+ /// - ID3D10Resource::Unmap
+ /// - ID3D11DeviceContext::Unmap
+ /// - ID3D12Resource::Unmap
+ /// - glUnmapBuffer
+ /// - glUnmapNamedBuffer
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource)
+ ///
+ UnmapBufferRegion,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DSurface9::LockRect
+ /// - IDirect3DVolume9::LockBox
+ /// - IDirect3DTexture9::LockRect
+ /// - IDirect3DVolumeTexture9::LockBox
+ /// - IDirect3DCubeTexture9::LockRect
+ /// - ID3D10Resource::Map
+ /// - ID3D11DeviceContext::Map
+ /// - ID3D12Resource::Map
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource, uint32_t subresource, const api::subresource_box *box, api::map_access access, api::subresource_data *data)
+ ///
+ MapTextureRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DSurface9::UnlockRect
+ /// - IDirect3DVolume9::UnlockBox
+ /// - IDirect3DTexture9::UnlockRect
+ /// - IDirect3DVolumeTexture9::UnlockBox
+ /// - IDirect3DCubeTexture9::UnlockRect
+ /// - ID3D10Resource::Unmap
+ /// - ID3D11DeviceContext::Unmap
+ /// - ID3D12Resource::Unmap
+ ///
+ /// Callback function signature: void (api::device *device, api::resource resource, uint32_t subresource)
+ ///
+ UnmapTextureRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D10Device::UpdateSubresource
+ /// - ID3D11DeviceContext::UpdateSubresource
+ /// - glBufferSubData
+ /// - glNamedBufferSubData
+ ///
+ /// Callback function signature: bool (api::device *device, const void *data, api::resource resource, uint64_t offset, uint64_t size)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Destination resource will be in the state.
+ ///
+ UpdateBufferRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D10Device::UpdateSubresource
+ /// - ID3D11DeviceContext::UpdateSubresource
+ /// - glTexSubData1D
+ /// - glTexSubData2D
+ /// - glTexSubData3D
+ /// - glTextureSubData1D
+ /// - glTextureSubData2D
+ /// - glTextureSubData3D
+ /// - glCompressedTexSubData1D
+ /// - glCompressedTexSubData2D
+ /// - glCompressedTexSubData3D
+ /// - glCompressedTextureSubData1D
+ /// - glCompressedTextureSubData2D
+ /// - glCompressedTextureSubData3D
+ ///
+ /// Callback function signature: bool (api::device *device, const api::subresource_data &data, api::resource resource, uint32_t subresource, const api::subresource_box *box)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Destination resource will be in the state.
+ ///
+ UpdateTextureRegion,
+
+ ///
+ /// Called after successful pipeline creation from:
+ ///
+ /// - IDirect3DDevice9::CreateVertexShader
+ /// - IDirect3DDevice9::CreatePixelShader
+ /// - IDirect3DDevice9::CreateVertexDeclaration
+ /// - ID3D10Device::CreateVertexShader
+ /// - ID3D10Device::CreateGeometryShader
+ /// - ID3D10Device::CreateGeometryShaderWithStreamOutput
+ /// - ID3D10Device::CreatePixelShader
+ /// - ID3D10Device::CreateInputLayout
+ /// - ID3D10Device::CreateBlendState
+ /// - ID3D10Device::CreateDepthStencilState
+ /// - ID3D10Device::CreateRasterizerState
+ /// - ID3D10Device1::CreateBlendState1
+ /// - ID3D11Device::CreateVertexShader
+ /// - ID3D11Device::CreateHullShader
+ /// - ID3D11Device::CreateDomainShader
+ /// - ID3D11Device::CreateGeometryShader
+ /// - ID3D11Device::CreateGeometryShaderWithStreamOutput
+ /// - ID3D11Device::CreatePixelShader
+ /// - ID3D11Device::CreateComputeShader
+ /// - ID3D11Device::CreateInputLayout
+ /// - ID3D11Device::CreateBlendState
+ /// - ID3D11Device::CreateDepthStencilState
+ /// - ID3D11Device::CreateRasterizerState
+ /// - ID3D11Device1::CreateBlendState1
+ /// - ID3D11Device1::CreateRasterizerState1
+ /// - ID3D11Device3::CreateRasterizerState2
+ /// - ID3D12Device::CreateComputePipelineState
+ /// - ID3D12Device::CreateGraphicsPipelineState
+ /// - ID3D12Device2::CreatePipelineState
+ /// - ID3D12Device5::CreateStateObject
+ /// - ID3D12Device7::AddToStateObject
+ /// - ID3D12PipelineLibrary::LoadComputePipeline
+ /// - ID3D12PipelineLibrary::LoadGraphicsPipeline
+ /// - ID3D12PipelineLibrary1::LoadPipeline
+ /// - glLinkProgram
+ /// - vkCreateComputePipelines
+ /// - vkCreateGraphicsPipelines
+ ///
+ /// Callback function signature: void (api::device *device, api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects, api::pipeline pipeline)
+ ///
+ ///
+ /// May be called multiple times with the same pipeline handle (whenever the pipeline is updated or its reference count is incremented).
+ ///
+ InitPipeline,
+
+ ///
+ /// Called on pipeline creation, before:
+ ///
+ /// - IDirect3DDevice9::CreateVertexShader
+ /// - IDirect3DDevice9::CreatePixelShader
+ /// - IDirect3DDevice9::CreateVertexDeclaration
+ /// - ID3D10Device::CreateVertexShader
+ /// - ID3D10Device::CreateGeometryShader
+ /// - ID3D10Device::CreateGeometryShaderWithStreamOutput
+ /// - ID3D10Device::CreatePixelShader
+ /// - ID3D10Device::CreateInputLayout
+ /// - ID3D10Device::CreateBlendState
+ /// - ID3D10Device::CreateDepthStencilState
+ /// - ID3D10Device::CreateRasterizerState
+ /// - ID3D10Device1::CreateBlendState1
+ /// - ID3D11Device::CreateVertexShader
+ /// - ID3D11Device::CreateHullShader
+ /// - ID3D11Device::CreateDomainShader
+ /// - ID3D11Device::CreateGeometryShader
+ /// - ID3D11Device::CreateGeometryShaderWithStreamOutput
+ /// - ID3D11Device::CreatePixelShader
+ /// - ID3D11Device::CreateComputeShader
+ /// - ID3D11Device::CreateInputLayout
+ /// - ID3D11Device::CreateBlendState
+ /// - ID3D11Device::CreateDepthStencilState
+ /// - ID3D11Device::CreateRasterizerState
+ /// - ID3D11Device1::CreateBlendState1
+ /// - ID3D11Device1::CreateRasterizerState1
+ /// - ID3D11Device3::CreateRasterizerState2
+ /// - ID3D12Device::CreateComputePipelineState
+ /// - ID3D12Device::CreateGraphicsPipelineState
+ /// - ID3D12Device2::CreatePipelineState
+ /// - ID3D12Device5::CreateStateObject
+ /// - glShaderSource
+ /// - vkCreateComputePipelines
+ /// - vkCreateGraphicsPipelines
+ ///
+ /// Callback function signature: bool (api::device *device, api::pipeline_layout layout, uint32_t subobject_count, const api::pipeline_subobject *subobjects)
+ ///
+ ///
+ /// To overwrite the pipeline description, modify desc in the callback and return , otherwise return .
+ ///
+ CreatePipeline,
+
+ ///
+ /// Called on pipeline destruction, before:
+ ///
+ /// - ID3D10VertexShader::Release
+ /// - ID3D10GeometryShader::Release
+ /// - ID3D10PixelShader::Release
+ /// - ID3D10InputLayout::Release
+ /// - ID3D10BlendState::Release
+ /// - ID3D10DepthStencilState::Release
+ /// - ID3D10RasterizerState::Release
+ /// - ID3D11VertexShader::Release
+ /// - ID3D11HullShader::Release
+ /// - ID3D11DomainShader::Release
+ /// - ID3D11GeometryShader::Release
+ /// - ID3D11PixelShader::Release
+ /// - ID3D11ComputeShader::Release
+ /// - ID3D11InputLayout::Release
+ /// - ID3D11BlendState::Release
+ /// - ID3D11DepthStencilState::Release
+ /// - ID3D11RasterizerState::Release
+ /// - ID3D12PipelineState::Release
+ /// - ID3D12StateObject::Release
+ /// - glDeleteProgram
+ /// - vkDestroyPipeline
+ ///
+ /// Callback function signature: void (api::device *device, api::pipeline pipeline)
+ ///
+ ///
+ /// Is not called in D3D9.
+ ///
+ DestroyPipeline,
+
+ ///
+ /// Called after successful pipeline layout creation from:
+ ///
+ /// - ID3D12Device::CreateRootSignature
+ /// - vkCreatePipelineLayout
+ ///
+ /// Callback function signature: void (api::device *device, uint32_t param_count, const api::pipeline_layout_param *params, api::pipeline_layout layout)
+ ///
+ ///
+ /// In case of D3D9, D3D10, D3D11 and OpenGL this is called during device initialization as well and behaves as if an implicit global pipeline layout was created.
+ ///
+ InitPipelineLayout,
+
+ ///
+ /// Called on pipeline layout creation, before:
+ ///
+ /// - ID3D12Device::CreateRootSignature
+ /// - vkCreatePipelineLayout
+ ///
+ /// Callback function signature: bool (api::device *device, uint32_t ¶m_count, api::pipeline_layout_param *¶ms)
+ ///
+ ///
+ /// Is not called in D3D9, D3D10, D3D11 or OpenGL.
+ ///
+ CreatePipelineLayout,
+
+ ///
+ /// Called on pipeline layout destruction, before:
+ ///
+ /// - ID3D12RootSignature::Release
+ /// - VkDestroyPipelineLayout
+ ///
+ /// Callback function signature: void (api::device *device, api::pipeline_layout layout)
+ ///
+ DestroyPipelineLayout,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12Device::CopyDescriptors
+ /// - ID3D12Device::CopyDescriptorsSimple
+ /// - vkUpdateDescriptorSets
+ ///
+ /// Callback function signature: bool (api::device *device, uint32_t count, const api::descriptor_table_copy *copies)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ CopyDescriptorTables,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12Device::CreateConstantBufferView
+ /// - ID3D12Device::CreateShaderResourceView
+ /// - ID3D12Device::CreateUnorderedAccessView
+ /// - ID3D12Device::CreateSampler
+ /// - vkUpdateDescriptorSets
+ ///
+ /// Callback function signature: bool (api::device *device, uint32_t count, const api::descriptor_table_update *updates)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ UpdateDescriptorTables,
+
+ ///
+ /// Called after successful query heap creation from:
+ ///
+ /// - ID3D12Device::CreateQueryHeap
+ /// - vkCreateQueryPool
+ ///
+ /// Callback function signature: void (api::device *device, api::query_type type, uint32_t size, api::query_heap heap)
+ ///
+ InitQueryHeap,
+
+ ///
+ /// Called on query heap creation, before:
+ ///
+ /// - ID3D12Device::CreateQueryHeap
+ /// - vkCreateQueryPool
+ ///
+ /// Callback function signature: bool (api::device *device, api::query_type type, uint32_t &size)
+ ///
+ CreateQueryHeap,
+
+ ///
+ /// Called on query heap destruction, before:
+ ///
+ /// - ID3D12QueryHeap::Release
+ /// - vkDestroyQueryPool
+ ///
+ /// Callback function signature: void (api::device *device, api::query_heap heap)
+ ///
+ DestroyQueryHeap,
+
+ ///
+ /// Called before:
+ ///
+ /// - vkGetQueryPoolResults
+ ///
+ /// Callback function signature: bool (api::device *device, api::query_heap heap, uint32_t first, uint32_t count, void *results, uint32_t stride)
+ ///
+ GetQueryHeapResults,
+
+ ///
+ /// Called after:
+ ///
+ /// - ID3D12GraphicsCommandList::ResourceBarrier
+ /// - ID3D12GraphicsCommandList7::Barrier
+ /// - vkCmdPipelineBarrier
+ /// - vkCmdPipelineBarrier2
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t count, const api::resource *resources, const api::resource_usage *old_states, const api::resource_usage *new_states)
+ ///
+ Barrier,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::BeginRenderPass
+ /// - vkCmdBeginRenderPass
+ /// - vkCmdBeginRenderPass2
+ /// - vkCmdNextSubpass
+ /// - vkCmdNextSubpass2
+ /// - vkCmdBeginRendering
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t count, const api::render_pass_render_target_desc *rts, const api::render_pass_depth_stencil_desc *ds)
+ ///
+ ///
+ /// The depth-stencil description argument is optional and may be (which indicates that no depth-stencil is used).
+ ///
+ BeginRenderPass,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::EndRenderPass
+ /// - vkCmdEndRenderPass
+ /// - vkCmdEndRenderPass2
+ /// - vkCmdNextSubpass
+ /// - vkCmdNextSubpass2
+ /// - vkCmdEndRendering
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list)
+ ///
+ EndRenderPass,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetRenderTarget
+ /// - IDirect3DDevice9::SetDepthStencilSurface
+ /// - ID3D10Device::OMSetRenderTargets
+ /// - ID3D11DeviceContext::OMSetRenderTargets
+ /// - ID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews
+ /// - ID3D12GraphicsCommandList::OMSetRenderTargets
+ /// - glBindFramebuffer
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t count, const api::resource_view *rtvs, api::resource_view dsv)
+ ///
+ BindRenderTargetsAndDepthStencil,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetVertexShader
+ /// - IDirect3DDevice9::SetPixelShader
+ /// - IDirect3DDevice9::SetVertexDeclaration
+ /// - IDirect3DDevice9::ProcessVertices
+ /// - ID3D10Device::VSSetShader
+ /// - ID3D10Device::GSSetShader
+ /// - ID3D10Device::PSSetShader
+ /// - ID3D10Device::IASetInputLayout
+ /// - ID3D10Device::OMSetBlendState
+ /// - ID3D10Device::OMSetDepthStencilState
+ /// - ID3D10Device::RSSetState
+ /// - ID3D11DeviceContext::VSSetShader
+ /// - ID3D11DeviceContext::HSSetShader
+ /// - ID3D11DeviceContext::DSSetShader
+ /// - ID3D11DeviceContext::GSSetShader
+ /// - ID3D11DeviceContext::PSSetShader
+ /// - ID3D11DeviceContext::CSSetShader
+ /// - ID3D11DeviceContext::IASetInputLayout
+ /// - ID3D11DeviceContext::OMSetBlendState
+ /// - ID3D11DeviceContext::OMSetDepthStencilState
+ /// - ID3D11DeviceContext::RSSetState
+ /// - ID3D12GraphicsCommandList::Reset
+ /// - ID3D12GraphicsCommandList::SetPipelineState
+ /// - ID3D12GraphicsCommandList4::SetPipelineState1
+ /// - glUseProgram
+ /// - glBindVertexArray
+ /// - vkCmdBindPipeline
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::pipeline_stage stages, api::pipeline pipeline)
+ ///
+ BindPipeline,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetRenderState
+ /// - ID3D10Device::IASetPrimitiveTopology
+ /// - ID3D10Device::OMSetBlendState
+ /// - ID3D10Device::OMSetDepthStencilState
+ /// - ID3D11DeviceContext::IASetPrimitiveTopology
+ /// - ID3D11DeviceContext::OMSetBlendState
+ /// - ID3D11DeviceContext::OMSetDepthStencilState
+ /// - ID3D12GraphicsCommandList::IASetPrimitiveTopology
+ /// - ID3D12GraphicsCommandList::OMSetBlendFactor
+ /// - ID3D12GraphicsCommandList::OMSetStencilRef
+ /// - gl(...)
+ /// - vkCmdSetDepthBias
+ /// - vkCmdSetBlendConstants
+ /// - vkCmdSetStencilCompareMask
+ /// - vkCmdSetStencilWriteMask
+ /// - vkCmdSetStencilReference
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t count, const api::dynamic_state *states, const uint32_t *values)
+ ///
+ BindPipelineStates,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetViewport
+ /// - IDirect3DDevice9::SetRenderTarget (implicitly updates the viewport)
+ /// - ID3D10Device::RSSetViewports
+ /// - ID3D11DeviceContext::RSSetViewports
+ /// - ID3D12GraphicsCommandList::RSSetViewports
+ /// - glViewport
+ /// - glViewportArrayv
+ /// - glViewportIndexedf
+ /// - glViewportIndexedfv
+ /// - vkCmdSetViewport
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t first, uint32_t count, const api::viewport *viewports)
+ ///
+ BindViewports,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetScissorRect
+ /// - ID3D10Device::RSSetScissorRects
+ /// - ID3D11DeviceContext::RSSetScissorRects
+ /// - ID3D12GraphicsCommandList::RSSetScissorRects
+ /// - glScissor
+ /// - glScissorArrayv
+ /// - glScissorIndexed
+ /// - glScissorIndexedv
+ /// - vkCmdSetScissor
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t first, uint32_t count, const api::rect *rects)
+ ///
+ BindScissorRects,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetVertexShaderConstantF
+ /// - IDirect3DDevice9::SetPixelShaderConstantF
+ /// - ID3D12GraphicsCommandList::SetComputeRoot32BitConstant
+ /// - ID3D12GraphicsCommandList::SetComputeRoot32BitConstants
+ /// - ID3D12GraphicsCommandList::SetGraphicsRoot32BitConstant
+ /// - ID3D12GraphicsCommandList::SetGraphicsRoot32BitConstants
+ /// - glUniform(...)
+ /// - vkCmdPushConstants
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, uint32_t first, uint32_t count, const void *values)
+ ///
+ PushConstants,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetTexture
+ /// - ID3D10Device::VSSetSamplers
+ /// - ID3D10Device::VSSetShaderResources
+ /// - ID3D10Device::VSSetConstantBuffers
+ /// - ID3D10Device::GSSetSamplers
+ /// - ID3D10Device::GSSetShaderResources
+ /// - ID3D10Device::GSSetConstantBuffers
+ /// - ID3D10Device::PSSetSamplers
+ /// - ID3D10Device::PSSetShaderResources
+ /// - ID3D10Device::PSSetConstantBuffers
+ /// - ID3D11DeviceContext::VSSetSamplers
+ /// - ID3D11DeviceContext::VSSetShaderResources
+ /// - ID3D11DeviceContext::VSSetConstantBuffers
+ /// - ID3D11DeviceContext::HSSetSamplers
+ /// - ID3D11DeviceContext::HSSetShaderResources
+ /// - ID3D11DeviceContext::HSSetConstantBuffers
+ /// - ID3D11DeviceContext::DSSetSamplers
+ /// - ID3D11DeviceContext::DSSetShaderResources
+ /// - ID3D11DeviceContext::DSSetConstantBuffers
+ /// - ID3D11DeviceContext::GSSetSamplers
+ /// - ID3D11DeviceContext::GSSetShaderResources
+ /// - ID3D11DeviceContext::GSSetConstantBuffers
+ /// - ID3D11DeviceContext::PSSetSamplers
+ /// - ID3D11DeviceContext::PSSetShaderResources
+ /// - ID3D11DeviceContext::PSSetConstantBuffers
+ /// - ID3D11DeviceContext::CSSetSamplers
+ /// - ID3D11DeviceContext::CSSetShaderResources
+ /// - ID3D11DeviceContext::CSSetUnorderedAccessViews
+ /// - ID3D11DeviceContext::CSSetConstantBuffers
+ /// - ID3D12GraphicsCommandList::SetComputeRootConstantBufferView
+ /// - ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView
+ /// - ID3D12GraphicsCommandList::SetComputeRootShaderResourceView
+ /// - ID3D12GraphicsCommandList::SetGraphicsRootShaderResourceView
+ /// - ID3D12GraphicsCommandList::SetComputeRootUnorderedAccessView
+ /// - ID3D12GraphicsCommandList::SetGraphicsRootUnorderedAccessView
+ /// - glBindBufferBase
+ /// - glBindBufferRange
+ /// - glBindBuffersBase
+ /// - glBindBuffersRange
+ /// - glBindTexture
+ /// - glBindImageTexture
+ /// - glBindTextures
+ /// - glBindImageTextures
+ /// - glBindTextureUnit
+ /// - glBindMultiTextureEXT
+ /// - vkCmdPushDescriptorSetKHR
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t layout_param, const api::descriptor_table_update &update)
+ ///
+ PushDescriptors,
+
+ ///
+ /// Called after:
+ ///
+ /// - ID3D12GraphicsCommandList::SetComputeRootSignature
+ /// - ID3D12GraphicsCommandList::SetGraphicsRootSignature
+ /// - ID3D12GraphicsCommandList::SetComputeRootDescriptorTable
+ /// - ID3D12GraphicsCommandList::SetGraphicsRootDescriptorTable
+ /// - vkCmdBindDescriptorSets
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::shader_stage stages, api::pipeline_layout layout, uint32_t first, uint32_t count, const api::descriptor_table *tables)
+ ///
+ BindDescriptorTables,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetIndices
+ /// - ID3D10Device::IASetIndexBuffer
+ /// - ID3D11DeviceContext::IASetIndexBuffer
+ /// - ID3D12GraphicsCommandList::IASetIndexBuffer
+ /// - glBindBuffer
+ /// - vkCmdBindIndexBuffer
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::resource buffer, uint64_t offset, uint32_t index_size)
+ ///
+ BindIndexBuffer,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::SetStreamSource
+ /// - ID3D10Device::IASetVertexBuffers
+ /// - ID3D11DeviceContext::IASetVertexBuffers
+ /// - ID3D12GraphicsCommandList::IASetVertexBuffers
+ /// - glBindBuffer
+ /// - glBindVertexBuffer
+ /// - glBindVertexBuffers
+ /// - vkCmdBindVertexBuffers
+ /// - vkCmdBindVertexBuffers2
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint32_t *strides)
+ ///
+ ///
+ /// The strides argument is optional and may be .
+ ///
+ BindVertexBuffers,
+
+ ///
+ /// Called after:
+ ///
+ /// - IDirect3DDevice9::ProcessVertices
+ /// - ID3D10Device::SOSetTargets
+ /// - ID3D11DeviceContext::SOSetTargets
+ /// - ID3D12GraphicsCommandList::SOSetTargets
+ /// - glBindBufferBase
+ /// - glBindBufferRange
+ /// - glBindBuffersBase
+ /// - glBindBuffersRange
+ /// - vkCmdBindTransformFeedbackBuffersEXT
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, uint32_t first, uint32_t count, const api::resource *buffers, const uint64_t *offsets, const uint64_t *max_sizes, const api::resource *counter_buffers, const uint64_t *counter_offsets)
+ ///
+ ///
+ /// The counter arguments are optional and may be .
+ ///
+ BindStreamOutputBuffers,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::DrawPrimitive
+ /// - IDirect3DDevice9::DrawPrimitiveUP
+ /// - IDirect3DDevice9::ProcessVertices
+ /// - ID3D10Device::Draw
+ /// - ID3D10Device::DrawInstanced
+ /// - ID3D11DeviceContext::Draw
+ /// - ID3D11DeviceContext::DrawInstanced
+ /// - ID3D12GraphicsCommandList::DrawInstanced
+ /// - glDrawArrays
+ /// - glDrawArraysInstanced
+ /// - glDrawArraysInstancedBaseInstance
+ /// - glMultiDrawArrays
+ /// - vkCmdDraw
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, uint32_t vertex_count, uint32_t instance_count, uint32_t first_vertex, uint32_t first_instance)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ Draw,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::DrawIndexedPrimitive
+ /// - IDirect3DDevice9::DrawIndexedPrimitiveUP
+ /// - ID3D10Device::DrawIndexed
+ /// - ID3D10Device::DrawIndexedInstanced
+ /// - ID3D11DeviceContext::DrawIndexed
+ /// - ID3D11DeviceContext::DrawIndexedInstanced
+ /// - ID3D12GraphicsCommandList::DrawIndexedInstanced
+ /// - glDrawElements
+ /// - glDrawElementsBaseVertex
+ /// - glDrawElementsInstanced
+ /// - glDrawElementsInstancedBaseVertex
+ /// - glDrawElementsInstancedBaseInstance
+ /// - glDrawElementsInstancedBaseVertexBaseInstance
+ /// - glMultiDrawElements
+ /// - glMultiDrawElementsBaseVertex
+ /// - vkCmdDrawIndexed
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, uint32_t index_count, uint32_t instance_count, uint32_t first_index, int32_t vertex_offset, uint32_t first_instance)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ DrawIndexed,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D11DeviceContext::Dispatch
+ /// - ID3D12GraphicsCommandList::Dispatch
+ /// - glDispatchCompute
+ /// - vkCmdDispatch
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ Dispatch = 54,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::DispatchMesh
+ /// - vkCmdDrawMeshTasksEXT
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, uint32_t group_count_x, uint32_t group_count_y, uint32_t group_count_z)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ DispatchMesh = 89,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::DispatchRays
+ /// - vkCmdTraceRaysKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource raygen, uint64_t raygen_offset, uint64_t raygen_size, api::resource miss, uint64_t miss_offset, uint64_t miss_size, uint64_t miss_stride, api::resource hit_group, uint64_t hit_group_offset, uint64_t hit_group_size, uint64_t hit_group_stride, api::resource callable, uint64_t callable_offset, uint64_t callable_size, uint64_t callable_stride, uint32_t width, uint32_t height, uint32_t depth)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// In case of D3D12 and Vulkan, the shader handle buffer handles may be zero with the buffers instead referred to via a device address passed in the related offset argument.
+ ///
+ DispatchRays = 90,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D11DeviceContext::DrawInstancedIndirect
+ /// - ID3D11DeviceContext::DrawIndexedInstancedIndirect
+ /// - ID3D11DeviceContext::DispatchIndirect
+ /// - ID3D12GraphicsCommandList::ExecuteIndirect
+ /// - glDrawArraysIndirect
+ /// - glDrawElementsIndirect
+ /// - glMultiDrawArraysIndirect
+ /// - glMultiDrawElementsIndirect
+ /// - glDispatchComputeIndirect
+ /// - vkCmdDrawIndirect
+ /// - vkCmdDrawIndexedIndirect
+ /// - vkCmdDispatchIndirect
+ /// - vkCmdTraceRaysIndirect2KHR
+ /// - vkCmdDrawMeshTasksIndirectEXT
+ /// - vkCmdDrawMeshTasksIndirectCountEXT
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::indirect_command type, api::resource buffer, uint64_t offset, uint32_t draw_count, uint32_t stride)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ DrawOrDispatchIndirect = 55,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::UpdateTexture
+ /// - IDirect3DDevice9::GetRenderTargetData
+ /// - ID3D10Device::CopyResource
+ /// - ID3D11DeviceContext::CopyResource
+ /// - ID3D12GraphicsCommandList::CopyResource
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, api::resource dest)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ ///
+ CopyResource,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::CopyBufferRegion
+ /// - glCopyBufferSubData
+ /// - glCopyNamedBufferSubData
+ /// - vkCmdCopyBuffer
+ /// - vkCmdCopyBuffer2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, uint64_t source_offset, api::resource dest, uint64_t dest_offset, uint64_t size)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ ///
+ CopyBufferRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::CopyTextureRegion
+ /// - vkCmdCopyBufferToImage
+ /// - vkCmdCopyBufferToImage2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, uint64_t source_offset, uint32_t row_length, uint32_t slice_height, api::resource dest, uint32_t dest_subresource, const api::subresource_box *dest_box)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ /// The subresource box argument is optional and may be (which indicates the entire subresource is referenced).
+ ///
+ CopyBufferToTexture,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::UpdateSurface
+ /// - IDirect3DDevice9::StretchRect
+ /// - ID3D10Device::CopySubresourceRegion
+ /// - ID3D11DeviceContext::CopySubresourceRegion
+ /// - ID3D12GraphicsCommandList::CopyTextureRegion
+ /// - glBlitFramebuffer
+ /// - glBlitNamedFramebuffer
+ /// - glCopyImageSubData
+ /// - glCopyTexSubImage1D
+ /// - glCopyTexSubImage2D
+ /// - glCopyTexSubImage3D
+ /// - glCopyTextureSubImage1D
+ /// - glCopyTextureSubImage2D
+ /// - glCopyTextureSubImage3D
+ /// - vkCmdBlitImage
+ /// - vkCmdBlitImage2
+ /// - vkCmdCopyImage
+ /// - vkCmdCopyImage2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, uint32_t source_subresource, const api::subresource_box *source_box, api::resource dest, uint32_t dest_subresource, const api::subresource_box *dest_box, api::filter_mode filter)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ /// The subresource box arguments are optional and may be (which indicates the entire subresource is used).
+ ///
+ CopyTextureRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::CopyTextureRegion
+ /// - vkCmdCopyImageToBuffer
+ /// - vkCmdCopyImageToBuffer2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, uint32_t source_subresource, const api::subresource_box *source_box, api::resource dest, uint64_t dest_offset, uint32_t row_length, uint32_t slice_height)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ /// The subresource box argument is optional and may be (which indicates the entire subresource is used).
+ ///
+ CopyTextureToBuffer,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::StretchRect
+ /// - ID3D10Device::ResolveSubresource
+ /// - ID3D11DeviceContext::ResolveSubresource
+ /// - ID3D12GraphicsCommandList::ResolveSubresource
+ /// - ID3D12GraphicsCommandList1::ResolveSubresourceRegion
+ /// - glBlitFramebuffer
+ /// - glBlitNamedFramebuffer
+ /// - vkCmdResolveImage
+ /// - vkCmdResolveImage2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource source, uint32_t source_subresource, const api::subresource_box *source_box, api::resource dest, uint32_t dest_subresource, int32_t dest_x, int32_t dest_y, int32_t dest_z, api::format format)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Source resource will be in the state.
+ /// Destination resource will be in the state.
+ /// The subresource box argument is optional and may be (which indicates the entire subresource is used).
+ ///
+ ResolveTextureRegion,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::Clear
+ /// - ID3D10Device::ClearDepthStencilView
+ /// - ID3D11DeviceContext::ClearDepthStencilView
+ /// - ID3D11DeviceContext1::ClearView (for depth-stencil views)
+ /// - ID3D12GraphicsCommandList::ClearDepthStencilView
+ /// - glClear
+ /// - glClearBufferfi
+ /// - glClearBufferfv
+ /// - glClearNamedFramebufferfi
+ /// - glClearNamedFramebufferfv
+ /// - vkCmdClearDepthStencilImage
+ /// - vkCmdClearAttachments
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view dsv, const float *depth, const uint8_t *stencil, uint32_t rect_count, const api::rect *rects)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Resource will be in the state.
+ /// One of the depth or stencil clear value arguments may be when the respective component is not cleared.
+ ///
+ ClearDepthStencilView,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::Clear
+ /// - IDirect3DDevice9::ColorFill
+ /// - ID3D10Device::ClearRenderTargetView
+ /// - ID3D11DeviceContext::ClearRenderTargetView
+ /// - ID3D11DeviceContext1::ClearView (for render target views)
+ /// - ID3D12GraphicsCommandList::ClearRenderTargetView
+ /// - glClear
+ /// - glClearBufferfv
+ /// - glClearNamedFramebufferfv
+ /// - vkCmdClearColorImage
+ /// - vkCmdClearAttachments
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view rtv, const float color[4], uint32_t rect_count, const api::rect *rects)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Resources will be in the state.
+ ///
+ ClearRenderTargetView,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D11DeviceContext::ClearUnorderedAccessViewUint
+ /// - ID3D12GraphicsCommandList::ClearUnorderedAccessViewUint
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view uav, const uint32_t values[4], uint32_t rect_count, const api::rect *rects)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Resource will be in the state.
+ ///
+ ClearUnorderedAccessViewUint,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D11DeviceContext::ClearUnorderedAccessViewFloat
+ /// - ID3D11DeviceContext1::ClearView (for unordered access views)
+ /// - ID3D12GraphicsCommandList::ClearUnorderedAccessViewFloat
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view uav, const float values[4], uint32_t rect_count, const api::rect *rects)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// Resource will be in the state.
+ ///
+ ClearUnorderedAccessViewFloat,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D10Device::GenerateMips
+ /// - ID3D11DeviceContext::GenerateMips
+ /// - glGenerateMipmap
+ /// - glGenerateTextureMipmap
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view srv)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ GenerateMipmaps,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::BeginQuery
+ /// - vkCmdBeginQuery
+ /// - vkCmdBeginQueryIndexedEXT
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::query_heap heap, api::query_type type, uint32_t index)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ BeginQuery,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::EndQuery
+ /// - vkCmdEndQuery
+ /// - vkCmdEndQueryIndexedEXT
+ /// - vkCmdWriteTimestamp
+ /// - vkCmdWriteTimestamp2
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::query_heap heap, api::query_type type, uint32_t index)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ EndQuery,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::ResolveQueryData
+ /// - vkCmdCopyQueryPoolResults
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::query_heap heap, api::query_type type, uint32_t first, uint32_t count, api::resource dest, uint64_t dest_offset, uint32_t stride)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ CopyQueryHeapResults = 69,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::CopyRaytracingAccelerationStructure
+ /// - vkCmdCopyAccelerationStructureKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::resource_view source, api::resource_view dest, api::acceleration_structure_copy_mode mode)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ ///
+ CopyAccelerationStructure = 91,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList4::BuildRaytracingAccelerationStructure
+ /// - vkCmdBuildAccelerationStructuresKHR
+ ///
+ /// Callback function signature: bool (api::command_list *cmd_list, api::acceleration_structure_type type, api::acceleration_structure_build_flags flags, uint32_t input_count, const api::acceleration_structure_build_input *inputs, api::resource scratch, uint64_t scratch_offset, api::resource_view source, api::resource_view dest, api::acceleration_structure_build_mode mode)
+ ///
+ ///
+ /// To prevent this command from being executed, return , otherwise return .
+ /// In case of D3D12 and Vulkan, the scratch buffer handle may be zero with the buffer instead referred to via a device address passed in the related offset argument.
+ /// Scratch buffer will be in the resource state.
+ ///
+ BuildAccelerationStructure = 92,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D12GraphicsCommandList::Reset
+ /// - vkBeginCommandBuffer
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list)
+ ///
+ ///
+ /// Is not called for immediate command lists (since they cannot be reset).
+ ///
+ ResetCommandList = 70,
+
+ ///
+ /// Called before:
+ ///
+ /// - ID3D11DeviceContext::FinishCommandList
+ /// - ID3D12GraphicsCommandList::Close
+ /// - vkEndCommandBuffer
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list)
+ ///
+ ///
+ /// Is not called for immediate command lists (since they cannot be closed).
+ ///
+ CloseCommandList,
+
+ ///
+ /// Called when a command list is submitted to a command queue (or an immediate command list is flushed), before:
+ ///
+ /// - IDirect3DDevice9::EndScene
+ /// - ID3D10Device::Flush
+ /// - ID3D11DeviceContext::Flush
+ /// - ID3D11DeviceContext3::Flush1
+ /// - ID3D12CommandQueue::ExecuteCommandLists
+ /// - glFlush
+ /// - vkQueueSubmit
+ ///
+ /// Callback function signature: void (api::command_queue *queue, api::command_list *cmd_list)
+ ///
+ ExecuteCommandList,
+
+ ///
+ /// Called when a secondary command list is executed on a primary command list, before:
+ ///
+ /// - ID3D11DeviceContext::ExecuteCommandList
+ /// - ID3D12GraphicsCommandList::ExecuteBundle
+ /// - vkCmdExecuteCommands
+ ///
+ /// In addition, called after:
+ ///
+ /// - ID3D11DeviceContext::FinishCommandList
+ ///
+ /// Callback function signature: void (api::command_list *cmd_list, api::command_list *secondary_cmd_list)
+ ///
+ ExecuteSecondaryCommandList,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDirect3DDevice9::Present
+ /// - IDirect3DDevice9Ex::PresentEx
+ /// - IDirect3DSwapChain9::Present
+ /// - IDXGISwapChain::Present
+ /// - IDXGISwapChain3::Present1
+ /// - ID3D12CommandQueueDownlevel::Present
+ /// - wglSwapBuffers
+ /// - vkQueuePresentKHR
+ /// - IVRCompositor::Submit
+ /// - xrEndFrame
+ ///
+ /// Callback function signature: void (api::command_queue *queue, api::swapchain *swapchain, const api::rect *source_rect, const api::rect *dest_rect, uint32_t dirty_rect_count, const api::rect *dirty_rects)
+ ///
+ ///
+ /// The source and destination rectangle arguments are optional and may be (which indicates the swap chain is presented in its entirety).
+ ///
+ Present,
+
+ ///
+ /// Called before:
+ ///
+ /// - IDXGISwapChain::SetFullscreenState
+ /// - vkAcquireFullScreenExclusiveModeEXT
+ /// - vkReleaseFullScreenExclusiveModeEXT
+ ///
+ /// Callback function signature: bool (api::swapchain *swapchain, bool fullscreen, void *hmonitor)
+ ///
+ ///
+ /// To prevent the fullscreen state from being changed, return , otherwise return .
+ ///
+ SetFullscreenState = 93,
+
+ ///
+ /// Called after ReShade has rendered its overlay.
+ /// Callback function signature: void (api::effect_runtime *runtime)
+ ///
+ ReShadePresent = 75,
+
+ ///
+ /// Called right before ReShade effects are rendered.
+ /// Callback function signature: void (api::effect_runtime *runtime, api::command_list *cmd_list, api::resource_view rtv, api::resource_view rtv_srgb)
+ ///
+ ReShadeBeginEffects,
+
+ ///
+ /// Called right after ReShade effects were rendered.
+ /// Callback function signature: void (api::effect_runtime *runtime, api::command_list *cmd_list, api::resource_view rtv, api::resource_view rtv_srgb)
+ ///
+ ReShadeFinishEffects,
+
+ ///
+ /// Called right after all ReShade effects were reloaded.
+ /// This occurs during effect runtime initialization or because the user pressed the "Reload" button in the overlay.
+ /// Any , and handles are invalidated when this event occurs and need to be queried again.
+ /// Callback function signature: void (api::effect_runtime *runtime)
+ ///
+ ReShadeReloadedEffects,
+
+ ///
+ /// Called before a uniform variable is changed, with the new value.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_uniform_variable variable, const void *new_value, size_t new_value_size)
+ ///
+ ///
+ /// To prevent the variable value from being changed, return , otherwise return .
+ /// The new value has the data type reported by . The new value size is in bytes.
+ ///
+ ReShadeSetUniformValue,
+
+ ///
+ /// Called before a technique is enabled or disabled, with the new state.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_technique technique, bool enabled)
+ ///
+ ///
+ /// To prevent the technique state from being changed, return , otherwise return .
+ ///
+ ReShadeSetTechniqueState,
+
+ ///
+ /// Called between the ImGui::NewFrame and ImGui::EndFrame calls for the ReShade overlay.
+ /// Can be used to perform custom Dear ImGui calls, but it is recommended to instead use to register a dedicated overlay.
+ /// Callback function signature: void (api::effect_runtime *runtime)
+ ///
+ ///
+ /// This is not called for effect runtimes in VR.
+ ///
+ ReShadeOverlay,
+
+ ///
+ /// Called after a screenshot was taken and saved to disk, with the path to the saved image file.
+ /// Callback function signature: void (api::effect_runtime *runtime, const char *path)
+ ///
+ ReShadeScreenshot,
+
+ ///
+ /// Called for each technique after it was rendered, usually between and .
+ /// Callback function signature: void (api::effect_runtime *runtime, api::effect_technique technique, api::command_list *cmd_list, api::resource_view rtv, api::resource_view rtv_srgb)
+ ///
+ ReShadeRenderTechnique,
+
+ ///
+ /// Called when all effects are about to be enabled or disabled.
+ /// Callback function signature: bool (api::effect_runtime *runtime, bool enabled)
+ ///
+ ///
+ /// To prevent the effects state from being changed, return , otherwise return .
+ ///
+ ReShadeSetEffectsState = 94,
+
+ ///
+ /// Called after a preset was loaded and applied.
+ /// This occurs after effect reloading or when the user chooses a new preset in the overlay.
+ /// Callback function signature: void (api::effect_runtime *runtime, const char *path)
+ ///
+ ReShadeSetCurrentPresetPath = 84,
+
+ ///
+ /// Called when the rendering order of loaded techniques is changed, with a handle array specifying the new order.
+ /// Callback function signature: bool (api::effect_runtime *runtime, size_t count, api::effect_technique *techniques)
+ ///
+ ///
+ /// To prevent the order from being changed, return , otherwise return .
+ ///
+ ReShadeReorderTechniques,
+
+ ///
+ /// Called when the ReShade overlay is about to be opened or closed.
+ /// Callback function signature: bool (api::effect_runtime *runtime, bool open, api::input_source source)
+ ///
+ ///
+ /// To prevent the overlay state from being changed, return , otherwise return .
+ ///
+ ReShadeOpenOverlay,
+
+ ///
+ /// Called when a uniform variable widget is added to the variable list in the overlay.
+ /// Can be used to replace with custom one or add widgets for specific uniform variables.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_uniform_variable variable)
+ ///
+ ///
+ /// To prevent the normal widget from being added to the overlay, return , otherwise return .
+ ///
+ ReShadeOverlayUniformVariable,
+
+ ///
+ /// Called when a technique is added to the technique list in the overlay.
+ /// Can be used to replace with custom one or add widgets for specific techniques.
+ /// Callback function signature: bool (api::effect_runtime *runtime, api::effect_technique technique)
+ ///
+ ///
+ /// To prevent the normal widget from being added to the overlay, return , otherwise return .
+ ///
+ ReShadeOverlayTechnique,
+ }
+}
diff --git a/Dalamud/Interface/Internal/ReShadeAddonInterface.Exports.cs b/Dalamud/Interface/Internal/ReShadeAddonInterface.Exports.cs
new file mode 100644
index 000000000..3dce1b79b
--- /dev/null
+++ b/Dalamud/Interface/Internal/ReShadeAddonInterface.Exports.cs
@@ -0,0 +1,59 @@
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+using TerraFX.Interop.Windows;
+
+using static TerraFX.Interop.Windows.Windows;
+
+namespace Dalamud.Interface.Internal;
+
+/// ReShade interface.
+[SuppressMessage(
+ "StyleCop.CSharp.LayoutRules",
+ "SA1519:Braces should not be omitted from multi-line child statement",
+ Justification = "Multiple fixed blocks")]
+internal sealed unsafe partial class ReShadeAddonInterface
+{
+ private static readonly ExportsStruct Exports;
+
+ static ReShadeAddonInterface()
+ {
+ foreach (var m in Process.GetCurrentProcess().Modules.Cast())
+ {
+ ExportsStruct e;
+ if (!GetProcAddressInto(m, nameof(e.ReShadeRegisterAddon), &e.ReShadeRegisterAddon) ||
+ !GetProcAddressInto(m, nameof(e.ReShadeUnregisterAddon), &e.ReShadeUnregisterAddon) ||
+ !GetProcAddressInto(m, nameof(e.ReShadeRegisterEvent), &e.ReShadeRegisterEvent) ||
+ !GetProcAddressInto(m, nameof(e.ReShadeUnregisterEvent), &e.ReShadeUnregisterEvent))
+ continue;
+
+ ReShadeModule = m;
+ Exports = e;
+ return;
+ }
+
+ return;
+
+ bool GetProcAddressInto(ProcessModule m, ReadOnlySpan name, void* res)
+ {
+ Span name8 = stackalloc byte[Encoding.UTF8.GetByteCount(name) + 1];
+ name8[Encoding.UTF8.GetBytes(name, name8)] = 0;
+ *(nint*)res = GetProcAddress((HMODULE)m.BaseAddress, (sbyte*)Unsafe.AsPointer(ref name8[0]));
+ return *(nint*)res != 0;
+ }
+ }
+
+ /// Gets the active ReShade module.
+ public static ProcessModule? ReShadeModule { get; private set; }
+
+ private struct ExportsStruct
+ {
+ public delegate* unmanaged ReShadeRegisterAddon;
+ public delegate* unmanaged ReShadeUnregisterAddon;
+ public delegate* unmanaged ReShadeRegisterEvent;
+ public delegate* unmanaged ReShadeUnregisterEvent;
+ }
+}
diff --git a/Dalamud/Interface/Internal/ReShadeAddonInterface.cs b/Dalamud/Interface/Internal/ReShadeAddonInterface.cs
new file mode 100644
index 000000000..156688c27
--- /dev/null
+++ b/Dalamud/Interface/Internal/ReShadeAddonInterface.cs
@@ -0,0 +1,176 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+using Dalamud.Hooking;
+
+using JetBrains.Annotations;
+
+using TerraFX.Interop.Windows;
+
+using static TerraFX.Interop.Windows.Windows;
+
+namespace Dalamud.Interface.Internal;
+
+/// ReShade interface.
+internal sealed unsafe partial class ReShadeAddonInterface : IDisposable
+{
+ private const int ReShadeApiVersion = 12;
+
+ private readonly HMODULE hDalamudModule;
+
+ private readonly Hook addonModuleResolverHook;
+
+ private readonly DelegateStorage reShadeOverlayDelegate;
+ private readonly DelegateStorage initSwapChainDelegate;
+ private readonly DelegateStorage destroySwapChainDelegate;
+
+ private ReShadeAddonInterface()
+ {
+ this.hDalamudModule = (HMODULE)Marshal.GetHINSTANCE(typeof(ReShadeAddonInterface).Assembly.ManifestModule);
+ if (!Exports.ReShadeRegisterAddon(this.hDalamudModule, ReShadeApiVersion))
+ throw new InvalidOperationException("ReShadeRegisterAddon failure.");
+
+ this.addonModuleResolverHook = Hook.FromImport(
+ ReShadeModule!,
+ "kernel32.dll",
+ nameof(GetModuleHandleExW),
+ 0,
+ this.GetModuleHandleExWDetour);
+
+ this.addonModuleResolverHook.Enable();
+ Exports.ReShadeRegisterEvent(
+ AddonEvent.ReShadeOverlay,
+ this.reShadeOverlayDelegate = new((ref ApiObject rt) => this.ReShadeOverlay?.Invoke(ref rt)));
+ Exports.ReShadeRegisterEvent(
+ AddonEvent.InitSwapChain,
+ this.initSwapChainDelegate = new((ref ApiObject rt) => this.InitSwapChain?.Invoke(ref rt)));
+ Exports.ReShadeRegisterEvent(
+ AddonEvent.DestroySwapChain,
+ this.destroySwapChainDelegate = new((ref ApiObject rt) => this.DestroySwapChain?.Invoke(ref rt)));
+ }
+
+ /// Finalizes an instance of the class.
+ ~ReShadeAddonInterface() => this.ReleaseUnmanagedResources();
+
+ /// Delegate for .
+ /// Reference to the ReShade runtime.
+ public delegate void ReShadeOverlayDelegate(ref ApiObject effectRuntime);
+
+ /// Delegate for .
+ /// Reference to the ReShade SwapChain wrapper.
+ public delegate void ReShadeInitSwapChain(ref ApiObject swapChain);
+
+ /// Delegate for .
+ /// Reference to the ReShade SwapChain wrapper.
+ public delegate void ReShadeDestroySwapChain(ref ApiObject swapChain);
+
+ private delegate BOOL GetModuleHandleExWDelegate(uint dwFlags, ushort* lpModuleName, HMODULE* phModule);
+
+ /// Called on .
+ public event ReShadeOverlayDelegate? ReShadeOverlay;
+
+ /// Called on .
+ public event ReShadeInitSwapChain? InitSwapChain;
+
+ /// Called on .
+ public event ReShadeDestroySwapChain? DestroySwapChain;
+
+ /// Registers Dalamud as a ReShade addon.
+ /// Initialized interface.
+ /// true on success.
+ public static bool TryRegisterAddon([NotNullWhen(true)] out ReShadeAddonInterface? r)
+ {
+ try
+ {
+ r = Exports.ReShadeRegisterAddon is null ? null : new();
+ return r is not null;
+ }
+ catch
+ {
+ r = null;
+ return false;
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.ReleaseUnmanagedResources();
+ GC.SuppressFinalize(this);
+ }
+
+ private void ReleaseUnmanagedResources()
+ {
+ Exports.ReShadeUnregisterEvent(AddonEvent.InitSwapChain, this.initSwapChainDelegate);
+ Exports.ReShadeUnregisterEvent(AddonEvent.DestroySwapChain, this.destroySwapChainDelegate);
+ Exports.ReShadeUnregisterEvent(AddonEvent.ReShadeOverlay, this.reShadeOverlayDelegate);
+ Exports.ReShadeUnregisterAddon(this.hDalamudModule);
+ this.addonModuleResolverHook.Disable();
+ this.addonModuleResolverHook.Dispose();
+ }
+
+ private BOOL GetModuleHandleExWDetour(uint dwFlags, ushort* lpModuleName, HMODULE* phModule)
+ {
+ if ((dwFlags & GET.GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) == 0)
+ return this.addonModuleResolverHook.Original(dwFlags, lpModuleName, phModule);
+ if ((dwFlags & GET.GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT) == 0)
+ return this.addonModuleResolverHook.Original(dwFlags, lpModuleName, phModule);
+ if (lpModuleName == this.initSwapChainDelegate ||
+ lpModuleName == this.destroySwapChainDelegate ||
+ lpModuleName == this.reShadeOverlayDelegate)
+ {
+ *phModule = this.hDalamudModule;
+ return BOOL.TRUE;
+ }
+
+ return this.addonModuleResolverHook.Original(dwFlags, lpModuleName, phModule);
+ }
+
+ /// ReShade effect runtime object.
+ [StructLayout(LayoutKind.Sequential)]
+ public struct ApiObject
+ {
+ /// The vtable.
+ public VTable* Vtbl;
+
+ /// Gets this object as a typed pointer.
+ /// Address of this instance.
+ /// This call is invalid if this object is not already fixed.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ApiObject* AsPointer() => (ApiObject*)Unsafe.AsPointer(ref this);
+
+ /// Gets the native object.
+ /// The native object.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public nint GetNative() => this.Vtbl->GetNative(this.AsPointer());
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T* GetNative() where T : unmanaged => (T*)this.GetNative();
+
+ /// VTable of .
+ [StructLayout(LayoutKind.Sequential)]
+ public struct VTable
+ {
+ ///
+ public delegate* unmanaged GetNative;
+ }
+ }
+
+ private readonly struct DelegateStorage where T : Delegate
+ {
+ [UsedImplicitly]
+ public readonly T Delegate;
+
+ public readonly void* Address;
+
+ public DelegateStorage(T @delegate)
+ {
+ this.Delegate = @delegate;
+ this.Address = (void*)Marshal.GetFunctionPointerForDelegate(@delegate);
+ }
+
+ public static implicit operator void*(DelegateStorage sto) => sto.Address;
+ }
+}
diff --git a/Dalamud/Interface/Internal/SwapChainHelper.cs b/Dalamud/Interface/Internal/SwapChainHelper.cs
index 09c1f52fd..e0c3f21a8 100644
--- a/Dalamud/Interface/Internal/SwapChainHelper.cs
+++ b/Dalamud/Interface/Internal/SwapChainHelper.cs
@@ -1,13 +1,7 @@
-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;
@@ -16,12 +10,6 @@ namespace Dalamud.Interface.Internal;
/// Helper for dealing with swap chains.
internal static unsafe class SwapChainHelper
{
- ///
- /// Gets the function pointer for ReShade's DXGISwapChain::on_present.
- /// Source.
- ///
- public static delegate* unmanaged ReshadeOnPresent { get; private set; }
-
/// Gets the game's active instance of IDXGISwapChain that is initialized.
/// Address of the game's instance of IDXGISwapChain, or null if not available (yet.)
public static IDXGISwapChain* GameDeviceSwapChain
@@ -92,102 +80,4 @@ internal static unsafe class SwapChainHelper
while (GameDeviceSwapChain is null)
Thread.Yield();
}
-
- /// Detects ReShade and populate .
- 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)reShadeDxgiPresent;
- }
-
- break;
- }
- catch (Exception e)
- {
- Log.Error(e, "Failed to get ReShade version info");
- break;
- }
- }
- }
}