11#include " pch.h"
22#include " DxgiFactory_Hooks.h"
3+ #include " DxgiSwapchainSizing.h"
34
45#include " D3D11_Hooks.h"
56#include " D3D12_Hooks.h"
@@ -116,6 +117,7 @@ void DxgiFactoryHooks::HookToFactory(IDXGIFactory* pFactory)
116117 IDXGIFactory2* factory2 = nullptr ;
117118 if (pFactory->QueryInterface (IID_PPV_ARGS (&factory2)) == S_OK )
118119 {
120+ void ** factory2VTable = *reinterpret_cast <void ***>(factory2);
119121 factory2->Release ();
120122
121123 if (o_CreateSwapChainForHwnd == nullptr )
@@ -133,6 +135,13 @@ void DxgiFactoryHooks::HookToFactory(IDXGIFactory* pFactory)
133135 if (o_CreateSwapChainForCoreWindow != nullptr )
134136 DetourAttach (&(PVOID &) o_CreateSwapChainForCoreWindow, DxgiFactoryHooks::CreateSwapChainForCoreWindow);
135137 }
138+
139+ if (o_CreateSwapChainForComposition == nullptr )
140+ {
141+ o_CreateSwapChainForComposition = (PFN_CreateSwapChainForComposition) factory2VTable[24 ];
142+ if (o_CreateSwapChainForComposition != nullptr )
143+ DetourAttach (&(PVOID &) o_CreateSwapChainForComposition, DxgiFactoryHooks::CreateSwapChainForComposition);
144+ }
136145 }
137146
138147 IDXGIFactory4* factory4 = nullptr ;
@@ -172,6 +181,7 @@ void DxgiFactoryHooks::HookToFactory(IDXGIFactory* pFactory)
172181 o_EnumAdapters1 = nullptr ;
173182 o_CreateSwapChainForHwnd = nullptr ;
174183 o_CreateSwapChainForCoreWindow = nullptr ;
184+ o_CreateSwapChainForComposition = nullptr ;
175185 o_EnumAdapterByLuid = nullptr ;
176186 o_EnumAdapterByGpuPreference = nullptr ;
177187 }
@@ -261,9 +271,14 @@ HRESULT DxgiFactoryHooks::CreateSwapChain(IDXGIFactory* realFactory, IUnknown* p
261271 return res;
262272 }
263273
264- if (pDesc->BufferDesc .Height < 100 || pDesc->BufferDesc .Width < 100 )
274+ DXGI_SWAP_CHAIN_DESC localDesc = *pDesc;
275+ const bool sizeToWindow = ResolveWindowSizedSwapchain (localDesc);
276+
277+ if (localDesc.BufferDesc .Height < 100 || localDesc.BufferDesc .Width < 100 )
265278 {
266- LOG_WARN (" Overlay call!" );
279+ LOG_WARN (" Overlay call! Width: {}, Height: {}, Format: {}, Count: {}, Hwnd: {:X}, Windowed: {}" ,
280+ pDesc->BufferDesc .Width , pDesc->BufferDesc .Height , (UINT ) pDesc->BufferDesc .Format ,
281+ pDesc->BufferCount , (SIZE_T ) pDesc->OutputWindow , pDesc->Windowed );
267282
268283 ScopedSkipDxgiLoadChecks skipDxgiLoadChecks {};
269284 ScopedSkipParentWrapping skipParentWrapping {};
@@ -272,8 +287,9 @@ HRESULT DxgiFactoryHooks::CreateSwapChain(IDXGIFactory* realFactory, IUnknown* p
272287 return res;
273288 }
274289
275- DXGI_SWAP_CHAIN_DESC localDesc {};
276- memcpy (&localDesc, pDesc, sizeof (DXGI_SWAP_CHAIN_DESC ));
290+ if (sizeToWindow)
291+ LOG_INFO (" CreateSwapChain: 0x0 size-to-window descriptor, Hwnd: {:X}, Count: {}, wrapping normally" ,
292+ (SIZE_T ) pDesc->OutputWindow , pDesc->BufferCount );
277293
278294 LOG_DEBUG (" Width: {}, Height: {}, Format: {}, Count: {}, Flags: {:X}, Hwnd: {:X}, Windowed: {}, SkipWrapping: {}" ,
279295 localDesc.BufferDesc .Width , localDesc.BufferDesc .Height , (UINT ) localDesc.BufferDesc .Format ,
@@ -525,6 +541,19 @@ HRESULT DxgiFactoryHooks::CreateSwapChain(IDXGIFactory* realFactory, IUnknown* p
525541
526542 if (result == S_OK )
527543 {
544+ if (sizeToWindow)
545+ {
546+ // Keep the dimensions actually created by DXGI authoritative for menu sizing.
547+ DXGI_SWAP_CHAIN_DESC resolvedDesc {};
548+ if ((*ppSwapChain)->GetDesc (&resolvedDesc) == S_OK )
549+ {
550+ LOG_INFO (" CreateSwapChain: resolved size-to-window swapchain to {}x{}" ,
551+ resolvedDesc.BufferDesc .Width , resolvedDesc.BufferDesc .Height );
552+ localDesc.BufferDesc .Width = resolvedDesc.BufferDesc .Width ;
553+ localDesc.BufferDesc .Height = resolvedDesc.BufferDesc .Height ;
554+ }
555+ }
556+
528557 State::Instance ().currentSwapchainDesc = localDesc;
529558 State::Instance ().swapchainInteropApi = SwapchainInteropApi::None;
530559
@@ -630,7 +659,7 @@ HRESULT DxgiFactoryHooks::CreateSwapChainForHwnd(IDXGIFactory2* realFactory, IUn
630659
631660 if (pDesc->Height < 100 || pDesc->Width < 100 )
632661 {
633- LOG_WARN (" Overlay call!" );
662+ LOG_WARN (" Overlay call! Width: {}, Height: {} " , pDesc-> Width , pDesc-> Height );
634663 HRESULT result;
635664
636665 {
@@ -1010,7 +1039,7 @@ HRESULT DxgiFactoryHooks::CreateSwapChainForCoreWindow(IDXGIFactory2* realFactor
10101039
10111040 if (pDesc->Height < 100 || pDesc->Width < 100 )
10121041 {
1013- LOG_WARN (" Overlay call!" );
1042+ LOG_WARN (" Overlay call! Width: {}, Height: {} " , pDesc-> Width , pDesc-> Height );
10141043
10151044 ScopedSkipDxgiLoadChecks skipDxgiLoadChecks {};
10161045 return realFactory->CreateSwapChainForCoreWindow (pDevice, pWindow, pDesc, pRestrictToOutput, ppSwapChain);
@@ -1099,6 +1128,68 @@ HRESULT DxgiFactoryHooks::CreateSwapChainForCoreWindow(IDXGIFactory2* realFactor
10991128 return result;
11001129}
11011130
1131+
1132+ HRESULT DxgiFactoryHooks::CreateSwapChainForComposition (IDXGIFactory2* realFactory, IUnknown* pDevice,
1133+ const DXGI_SWAP_CHAIN_DESC1 * pDesc,
1134+ IDXGIOutput* pRestrictToOutput,
1135+ IDXGISwapChain1** ppSwapChain)
1136+ {
1137+ // Always call the trampoline, including pass-through/error cases. Calling the detoured virtual
1138+ // method here re-enters this hook. Keep the composition descriptor intact: notably, a desktop
1139+ // VSync override must not turn its FLIP_SEQUENTIAL swap effect into FLIP_DISCARD.
1140+ const bool passThrough = State::Instance ().vulkanCreatingSC || _skipFGSwapChainCreation ||
1141+ pDevice == nullptr || pDesc == nullptr || ppSwapChain == nullptr ||
1142+ pDesc->Width < 100 || pDesc->Height < 100 ;
1143+ if (pDesc != nullptr && (pDesc->Width < 100 || pDesc->Height < 100 ))
1144+ LOG_WARN (" Composition overlay/helper call! Width: {}, Height: {}" , pDesc->Width , pDesc->Height );
1145+
1146+ HRESULT result;
1147+ {
1148+ ScopedSkipDxgiLoadChecks skipDxgiLoadChecks {};
1149+ ScopedSkipParentWrapping skipParentWrapping {};
1150+ result = o_CreateSwapChainForComposition (realFactory, pDevice, pDesc, pRestrictToOutput, ppSwapChain);
1151+ }
1152+ if (passThrough || FAILED (result) || *ppSwapChain == nullptr )
1153+ return result;
1154+
1155+ WrappedIDXGISwapChain4* existing = nullptr ;
1156+ if ((*ppSwapChain)->QueryInterface (IID_PPV_ARGS (&existing)) == S_OK )
1157+ {
1158+ existing->Release ();
1159+ return result;
1160+ }
1161+
1162+ DXGI_SWAP_CHAIN_DESC1 resolved {};
1163+ if (FAILED ((*ppSwapChain)->GetDesc1 (&resolved)))
1164+ return result; // Do not install a wrapper with unknown dimensions/flags.
1165+
1166+ // A composition chain has no native HWND. Use only an eligible window in this process, and
1167+ // defer overlay initialization to Present if no unambiguous window exists yet. Do not borrow
1168+ // another application's foreground window. HWND association remains a best-effort fallback.
1169+ const HWND window = FindCompositionWindow ();
1170+ IDXGISwapChain1* const created = *ppSwapChain;
1171+ auto * wrapped = new WrappedIDXGISwapChain4 (created, pDevice, window, resolved.Flags , false , true );
1172+ *ppSwapChain = wrapped;
1173+
1174+ // Preserve the returned COM/proxy chain: the wrapper owns its original reference. Unwrapping it
1175+ // here can leak an outer proxy and bypass another provider's presentation path.
1176+ State::Instance ().currentRealSwapchain = created;
1177+ State::Instance ().currentSwapchain = wrapped;
1178+ State::Instance ().currentWrappedSwapchain = wrapped;
1179+ State::Instance ().swapchainInteropApi = SwapchainInteropApi::None;
1180+ State::Instance ().SCAllowTearing = (resolved.Flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING ) != 0 ;
1181+ State::Instance ().SCLastFlags = resolved.Flags ;
1182+ State::Instance ().realExclusiveFullscreen = false ;
1183+ State::Instance ().screenWidth = (float ) resolved.Width ;
1184+ State::Instance ().screenHeight = (float ) resolved.Height ;
1185+ DXGI_SWAP_CHAIN_DESC legacy {};
1186+ if (SUCCEEDED (created->GetDesc (&legacy)))
1187+ State::Instance ().currentSwapchainDesc = legacy;
1188+ LOG_INFO (" Wrapped composition swapchain {}x{}, window {:X}; plain presentation, no FG swapchain replacement" ,
1189+ resolved.Width , resolved.Height , (SIZE_T ) window);
1190+ return result;
1191+ }
1192+
11021193HRESULT DxgiFactoryHooks::DLSSGCreateSwapChain (IDXGIFactory* realFactory, IUnknown* pDevice,
11031194 DXGI_SWAP_CHAIN_DESC * pDesc, IDXGISwapChain** ppSwapChain)
11041195{
@@ -1131,9 +1222,12 @@ HRESULT DxgiFactoryHooks::DLSSGCreateSwapChain(IDXGIFactory* realFactory, IUnkno
11311222 return res;
11321223 }
11331224
1134- if (pDesc->BufferDesc .Height < 100 || pDesc->BufferDesc .Width < 100 )
1225+ DXGI_SWAP_CHAIN_DESC localDesc = *pDesc;
1226+ ResolveWindowSizedSwapchain (localDesc);
1227+
1228+ if (localDesc.BufferDesc .Height < 100 || localDesc.BufferDesc .Width < 100 )
11351229 {
1136- LOG_WARN (" Overlay call!" );
1230+ LOG_WARN (" Overlay call! Width: {}, Height: {} " , pDesc-> BufferDesc . Width , pDesc-> BufferDesc . Height );
11371231
11381232 ScopedSkipDxgiLoadChecks skipDxgiLoadChecks {};
11391233 ScopedSkipParentWrapping skipParentWrapping {};
@@ -1142,9 +1236,6 @@ HRESULT DxgiFactoryHooks::DLSSGCreateSwapChain(IDXGIFactory* realFactory, IUnkno
11421236 return res;
11431237 }
11441238
1145- DXGI_SWAP_CHAIN_DESC localDesc {};
1146- memcpy (&localDesc, pDesc, sizeof (DXGI_SWAP_CHAIN_DESC ));
1147-
11481239 LOG_DEBUG (" Width: {}, Height: {}, Format: {}, Count: {}, Flags: {:X}, Hwnd: {:X}, Windowed: {}, SkipWrapping: {}" ,
11491240 localDesc.BufferDesc .Width , localDesc.BufferDesc .Height , (UINT ) localDesc.BufferDesc .Format ,
11501241 localDesc.BufferCount , localDesc.Flags , (SIZE_T ) localDesc.OutputWindow , localDesc.Windowed ,
@@ -1427,7 +1518,7 @@ HRESULT DxgiFactoryHooks::DLSSGCreateSwapChainForHwnd(IDXGIFactory2* realFactory
14271518
14281519 if (pDesc->Height < 100 || pDesc->Width < 100 )
14291520 {
1430- LOG_WARN (" Overlay call!" );
1521+ LOG_WARN (" Overlay call! Width: {}, Height: {} " , pDesc-> Width , pDesc-> Height );
14311522 HRESULT result;
14321523
14331524 {
@@ -1722,7 +1813,7 @@ HRESULT DxgiFactoryHooks::DLSSGCreateSwapChainForCoreWindow(IDXGIFactory2* realF
17221813
17231814 if (pDesc->Height < 100 || pDesc->Width < 100 )
17241815 {
1725- LOG_WARN (" Overlay call!" );
1816+ LOG_WARN (" Overlay call! Width: {}, Height: {} " , pDesc-> Width , pDesc-> Height );
17261817
17271818 ScopedSkipDxgiLoadChecks skipDxgiLoadChecks {};
17281819 return realFactory->CreateSwapChainForCoreWindow (pDevice, pWindow, pDesc, pRestrictToOutput, ppSwapChain);
0 commit comments