@@ -10,6 +10,7 @@ bool ShowMenu = false, ImGui_Initialised = false;
1010HWND g_GameWindow = nullptr ;
1111WNDPROC g_OriginalWndProc = nullptr ;
1212static HMODULE g_Module = nullptr ;
13+ static int g_SelectedBackend = -1 ; // set by C# via SetBackend()
1314
1415static int g_WndProcMsgCount = 0 ;
1516LRESULT APIENTRY WndProc (HWND h, UINT m, WPARAM w, LPARAM l) {
@@ -20,13 +21,13 @@ LRESULT APIENTRY WndProc(HWND h, UINT m, WPARAM w, LPARAM l) {
2021HRESULT APIENTRY hkPresent (IDXGISwapChain* sc, UINT sync, UINT flags) {
2122 if (!ImGui_Initialised) {
2223 if (imgui_callbacks.init_callback == nullptr ) return oPresent (sc, sync, flags);
23- DEBUG_LOG (" hkPresent: first frame init, backend=%d" , g_KieroBackend );
24+ DEBUG_LOG (" hkPresent: first frame init, backend=%d" , g_SelectedBackend );
2425 {
2526 DXGI_SWAP_CHAIN_DESC sd; sc->GetDesc (&sd);
2627 g_GameWindow = sd.OutputWindow ;
2728 DEBUG_LOG (" hkPresent: OutputWindow=%p (%dx%d)" , g_GameWindow, sd.BufferDesc .Width , sd.BufferDesc .Height );
2829 }
29- switch (g_KieroBackend ) {
30+ switch (g_SelectedBackend ) {
3031 case 2 : DX9::Init (sc); break ;
3132 case 1 : DX11::Init (sc); break ;
3233 case 0 : DX12::Init (sc); break ;
@@ -36,7 +37,7 @@ HRESULT APIENTRY hkPresent(IDXGISwapChain* sc, UINT sync, UINT flags) {
3637 ImGui_ImplWin32_Init (g_GameWindow);
3738 DEBUG_LOG (" hkPresent: GL/VK init via C#, no native backend" );
3839 break ;
39- default : DEBUG_LOG (" hkPresent: unknown backend=%d, skipping init" , g_KieroBackend ); break ;
40+ default : DEBUG_LOG (" hkPresent: unknown backend=%d, skipping init" , g_SelectedBackend ); break ;
4041 }
4142 g_OriginalWndProc = (WNDPROC )SetWindowLongPtr (g_GameWindow, GWLP_WNDPROC , (__int3264)(LONG_PTR )WndProc);
4243 ImGui_Initialised = true ;
@@ -60,7 +61,7 @@ HRESULT APIENTRY hkPresent(IDXGISwapChain* sc, UINT sync, UINT flags) {
6061 io->DisplaySize .x = (float )sd.BufferDesc .Width ; io->DisplaySize .y = (float )sd.BufferDesc .Height ; }
6162 ImGui_ImplWin32_NewFrame ();
6263
63- switch (g_KieroBackend ) {
64+ switch (g_SelectedBackend ) {
6465 case 4 : case 3 : // VK/GL: C# render only
6566 if (imgui_callbacks.render_callback ) imgui_callbacks.render_callback (); break ;
6667 case 2 : DX9::Render (sc); break ;
@@ -86,43 +87,69 @@ DWORD WINAPI MainThread(LPVOID) {
8687 Sleep (100 );
8788 }
8889
89- // ---- kiero2 backend detection (explicit locate, no macros) ----
90+ if (g_SelectedBackend < 0 || g_SelectedBackend > 4 ) {
91+ DEBUG_LOG (" MainThread: invalid backend=%d, no hooks installed" , g_SelectedBackend);
92+ return 1 ;
93+ }
94+
9095 MH_Initialize ();
91- {
92- kiero::D3D12Output d3d12;
93- kiero::D3D11Output d3d11;
94- kiero::D3D9Output d3d9;
95- kiero::OpenGLOutput gl;
96- kiero::VulkanOutput vk;
97-
98- if (kiero::locate<kiero::Implementation_D3D12>(nullptr , &d3d12) == kiero::Error_Nil)
99- { g_KieroBackend = 0 ; g_KieroD3D12 = d3d12; DEBUG_LOG (" MainThread: backend=D3D12" ); }
100- else if (kiero::locate<kiero::Implementation_D3D11>(nullptr , &d3d11) == kiero::Error_Nil)
101- { g_KieroBackend = 1 ; g_KieroD3D11 = d3d11; DEBUG_LOG (" MainThread: backend=D3D11" ); }
102- else if (kiero::locate<kiero::Implementation_D3D9>(nullptr , &d3d9) == kiero::Error_Nil)
103- { g_KieroBackend = 2 ; g_KieroD3D9 = d3d9; DEBUG_LOG (" MainThread: backend=D3D9" ); }
104- else if (kiero::locate<kiero::Implementation_OpenGL>(nullptr , &gl) == kiero::Error_Nil)
105- { g_KieroBackend = 3 ; g_KieroOpenGL = gl; DEBUG_LOG (" MainThread: backend=OpenGL" ); }
106- else if (kiero::locate<kiero::Implementation_Vulkan>(nullptr , &vk) == kiero::Error_Nil)
107- { g_KieroBackend = 4 ; g_KieroVulkan = vk; DEBUG_LOG (" MainThread: backend=Vulkan" ); }
108- else {
109- DEBUG_LOG (" MainThread: no backend detected!" );
110- return 1 ;
111- }
96+ DEBUG_LOG (" MainThread: backend=%d (0=D3D12 1=D3D11 2=D3D9 3=GL 4=VK)" , g_SelectedBackend);
97+
98+ // GL/VK: no DXGI swapchain to hook — call init directly, C# handles everything
99+ if (g_SelectedBackend >= 3 ) {
100+ if (imgui_callbacks.init_callback ) imgui_callbacks.init_callback ();
101+ DEBUG_LOG (" MainThread: GL/VK backend, C# handles rendering, no native hooks" );
102+ return 0 ;
112103 }
113- DEBUG_LOG ( " MainThread: backend=%d (0=D3D12 1=D3D11 2=D3D9 3=GL 4=VK) " , g_KieroBackend);
114- if (g_KieroBackend == 0 ) {
104+
105+ if (g_SelectedBackend == 0 ) {
115106 void * t = D3D12_CQ (10 );
116107 DEBUG_LOG (" MainThread: D3D12 CQ[10]=%p (ExecuteCommandLists)" , t);
117108 if (t) { MH_CreateHook (t, (LPVOID )hkExecuteCommandLists, (void **)&oExecuteCommandLists); MH_EnableHook (t); }
118109 }
119- void * prTarget = g_KieroBackend == 0 ? D3D12_SWAP (8 ) : g_KieroBackend == 1 ? D3D11_SWAP (8 ) : D3D9_DEV (17 );
110+ void * prTarget = g_SelectedBackend == 0 ? D3D12_SWAP (8 ) : g_SelectedBackend == 1 ? D3D11_SWAP (8 ) : D3D9_DEV (17 );
120111 DEBUG_LOG (" MainThread: Present target=%p, installing hook..." , prTarget);
121112 if (prTarget) { MH_CreateHook (prTarget, (LPVOID )hkPresent, (void **)&oPresent); MH_EnableHook (prTarget); }
122113 DEBUG_LOG (" MainThread: hooks installed, oPresent=%p" , oPresent);
123114 return 0 ;
124115}
125116
117+ // ---- C# API ----
118+
119+ extern " C" __declspec(dllexport) int __cdecl GetAvailableBackends () {
120+ int mask = 0 ;
121+ kiero::D3D12Output d3d12;
122+ kiero::D3D11Output d3d11;
123+ kiero::D3D9Output d3d9;
124+ kiero::OpenGLOutput gl;
125+ kiero::VulkanOutput vk;
126+
127+ // else-if chain: first match wins (D3D12 locate may false-positive on D3D11 devices)
128+ if (kiero::locate<kiero::Implementation_D3D11>(nullptr , &d3d11) == kiero::Error_Nil)
129+ { mask = 2 ; g_KieroD3D11 = d3d11; DEBUG_LOG (" GetAvailableBackends: D3D11" ); }
130+ else if (kiero::locate<kiero::Implementation_D3D12>(nullptr , &d3d12) == kiero::Error_Nil)
131+ { mask = 1 ; g_KieroD3D12 = d3d12; DEBUG_LOG (" GetAvailableBackends: D3D12" ); }
132+ else if (kiero::locate<kiero::Implementation_D3D9>(nullptr , &d3d9) == kiero::Error_Nil)
133+ { mask = 4 ; g_KieroD3D9 = d3d9; DEBUG_LOG (" GetAvailableBackends: D3D9" ); }
134+ else if (kiero::locate<kiero::Implementation_OpenGL>(nullptr , &gl) == kiero::Error_Nil)
135+ { mask = 8 ; g_KieroOpenGL = gl; DEBUG_LOG (" GetAvailableBackends: OpenGL" ); }
136+ else if (kiero::locate<kiero::Implementation_Vulkan>(nullptr , &vk) == kiero::Error_Nil)
137+ { mask = 16 ; g_KieroVulkan = vk; DEBUG_LOG (" GetAvailableBackends: Vulkan" ); }
138+
139+ DEBUG_LOG (" GetAvailableBackends: mask=0x%02X" , mask);
140+ return mask;
141+ }
142+
143+ extern " C" __declspec(dllexport) int __cdecl SetBackend (int backend) {
144+ if (backend < 0 || backend > 4 ) {
145+ DEBUG_LOG (" SetBackend: invalid backend=%d" , backend);
146+ return 1 ;
147+ }
148+ g_SelectedBackend = backend;
149+ DEBUG_LOG (" SetBackend: backend=%d" , backend);
150+ return 0 ;
151+ }
152+
126153extern " C" __declspec(dllexport) int __cdecl Init (ImGuiInitCallbackFn ic, ImGuiShutdownCallbackFn sc, ImGuiRenderCallbackFn rc) {
127154 DEBUG_LOG (" Init: bridge mode, init_cb=%p shutdown_cb=%p render_cb=%p" , ic, sc, rc);
128155 imgui_callbacks = { ic, sc, rc }; g_BridgeMode = true ;
0 commit comments