From fa52c9e985d9b718850c71c4e1c5659a3bfab5d5 Mon Sep 17 00:00:00 2001 From: Orange Date: Wed, 6 May 2026 22:00:23 +0300 Subject: [PATCH] added opengl for linux --- CMakeLists.txt | 3 + include/omath/hooks/hooks_manager.hpp | 46 +++++++++- source/hooks/hooks_manager.cpp | 121 ++++++++++++++++++-------- 3 files changed, 130 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d9eae0..fd24fcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,6 +114,9 @@ if (OMATH_ENABLE_HOOKING) if (WIN32) target_link_libraries(${PROJECT_NAME} PRIVATE d3d9 d3d11 d3d12 dxgi opengl32 gdi32) + elseif (UNIX AND NOT APPLE) + find_package(OpenGL REQUIRED) + target_link_libraries(${PROJECT_NAME} PRIVATE OpenGL::GL ${CMAKE_DL_LIBS}) endif () endif () diff --git a/include/omath/hooks/hooks_manager.hpp b/include/omath/hooks/hooks_manager.hpp index 398fd84..ab2db33 100644 --- a/include/omath/hooks/hooks_manager.hpp +++ b/include/omath/hooks/hooks_manager.hpp @@ -7,6 +7,7 @@ #include #include +#ifdef _WIN32 #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif @@ -17,6 +18,12 @@ #include #include #include +#endif // _WIN32 + +#ifdef __linux__ +#include +#endif // __linux__ + #include namespace omath::hooks @@ -26,6 +33,7 @@ namespace omath::hooks HooksManager() = default; public: +#ifdef _WIN32 // IDXGISwapChain callbacks — shared between DX11 and DX12 (same interface, same signature). using present_callback = std::function; using resize_buffers_callback = std::function; @@ -38,11 +46,17 @@ namespace omath::hooks using dx9_reset_callback = std::function; using dx9_end_scene_callback = std::function; - // OpenGL callbacks. Fires before the hooked buffer swap function calls the original. + // OpenGL callback — Windows. Fires before the hooked buffer swap function calls the original. using opengl_swap_buffers_callback = std::function; // Return nullopt to pass the message to the original WndProc; return a value to intercept it. using wnd_proc_callback = std::function(HWND, UINT, WPARAM, LPARAM)>; +#endif // _WIN32 + +#ifdef __linux__ + // OpenGL/GLX callback — Linux. Fires before glXSwapBuffers calls the original. + using opengl_swap_buffers_callback = std::function; +#endif // __linux__ template using callback_ptr = std::shared_ptr; @@ -52,6 +66,7 @@ namespace omath::hooks HooksManager& operator=(const HooksManager&) = delete; ~HooksManager(); +#ifdef _WIN32 [[nodiscard]] bool hook_dx9(); void unhook_dx9(); void set_on_dx9_present(dx9_present_callback callback); @@ -63,11 +78,13 @@ namespace omath::hooks [[nodiscard]] bool hook_dx12(); void unhook_dx12(); +#endif // _WIN32 [[nodiscard]] bool hook_opengl(); void unhook_opengl(); void set_on_opengl_swap_buffers(opengl_swap_buffers_callback callback); +#ifdef _WIN32 // Present and ResizeBuffers callbacks fire for whichever of DX11/DX12 is hooked. void set_on_present(present_callback callback); void set_on_resize_buffers(resize_buffers_callback callback); @@ -76,8 +93,10 @@ namespace omath::hooks [[nodiscard]] bool hook_wnd_proc(HWND hwnd); void unhook_wnd_proc(); void set_on_wnd_proc(wnd_proc_callback callback); +#endif // _WIN32 private: +#ifdef _WIN32 [[nodiscard]] static HRESULT __stdcall dx9_present_detour(IDirect3DDevice9* p_device, const RECT* p_source_rect, const RECT* p_dest_rect, HWND h_dest_window_override, @@ -109,9 +128,15 @@ namespace omath::hooks [[nodiscard]] static LRESULT __stdcall wnd_proc_detour(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param); +#endif // _WIN32 + +#ifdef __linux__ + static void opengl_glx_swap_buffers_detour(Display* display, GLXDrawable drawable); +#endif // __linux__ mutable std::shared_mutex m_hook_state_mutex; +#ifdef _WIN32 mutable std::shared_mutex m_dx9_present_mutex; mutable std::shared_mutex m_dx9_reset_mutex; mutable std::shared_mutex m_dx9_end_scene_mutex; @@ -120,13 +145,15 @@ namespace omath::hooks mutable std::shared_mutex m_resize_buffers_mutex; mutable std::shared_mutex m_execute_command_lists_mutex; - mutable std::shared_mutex m_opengl_swap_buffers_mutex; mutable std::shared_mutex m_wnd_proc_mutex; +#endif // _WIN32 + mutable std::shared_mutex m_opengl_swap_buffers_mutex; + +#ifdef _WIN32 bool m_is_dx9_hooked = false; bool m_is_dx11_hooked = false; bool m_is_dx12_hooked = false; - bool m_is_opengl_hooked = false; bool m_is_wnd_proc_hooked = false; HWND m_hooked_hwnd = nullptr; @@ -145,7 +172,15 @@ namespace omath::hooks safetyhook::InlineHook m_opengl_wgl_swap_buffers_hook; safetyhook::InlineHook m_opengl_swap_buffers_hook; +#endif // _WIN32 +#ifdef __linux__ + safetyhook::InlineHook m_opengl_glx_swap_buffers_hook; +#endif // __linux__ + + bool m_is_opengl_hooked = false; + +#ifdef _WIN32 callback_ptr m_dx9_present_cb; callback_ptr m_dx9_reset_cb; callback_ptr m_dx9_end_scene_cb; @@ -153,8 +188,11 @@ namespace omath::hooks callback_ptr m_present_cb; callback_ptr m_resize_buffers_cb; callback_ptr m_execute_command_lists_cb; - callback_ptr m_opengl_swap_buffers_cb; + callback_ptr m_wnd_proc_cb; +#endif // _WIN32 + + callback_ptr m_opengl_swap_buffers_cb; }; } // namespace omath::hooks diff --git a/source/hooks/hooks_manager.cpp b/source/hooks/hooks_manager.cpp index 459fe2a..cc35cab 100644 --- a/source/hooks/hooks_manager.cpp +++ b/source/hooks/hooks_manager.cpp @@ -1,10 +1,18 @@ #include "omath/hooks/hooks_manager.hpp" #ifdef OMATH_ENABLE_HOOKING + +#ifdef _WIN32 #include +#endif // _WIN32 + +#ifdef __linux__ +#include +#endif // __linux__ namespace { +#ifdef _WIN32 thread_local bool g_is_inside_opengl_swap_buffers = false; class DummyWindow final @@ -164,6 +172,7 @@ namespace vtable_fn(objs.command_queue, 10), // ID3D12CommandQueue::ExecuteCommandLists }; } +#endif // _WIN32 } // namespace namespace omath::hooks @@ -176,13 +185,16 @@ namespace omath::hooks HooksManager::~HooksManager() { +#ifdef _WIN32 unhook_wnd_proc(); unhook_dx9(); unhook_dx11(); unhook_dx12(); +#endif // _WIN32 unhook_opengl(); } +#ifdef _WIN32 bool HooksManager::hook_dx9() { std::unique_lock lock(m_hook_state_mutex); @@ -430,13 +442,6 @@ namespace omath::hooks m_is_opengl_hooked = false; } - void HooksManager::set_on_opengl_swap_buffers(opengl_swap_buffers_callback callback) - { - std::unique_lock lock(m_opengl_swap_buffers_mutex); - m_opengl_swap_buffers_cb = - callback ? std::make_shared(std::move(callback)) : nullptr; - } - void HooksManager::set_on_present(present_callback callback) { std::unique_lock lock(m_present_mutex); @@ -616,47 +621,41 @@ namespace omath::hooks auto& mgr = get(); if (!g_is_inside_opengl_swap_buffers) + return mgr.m_opengl_wgl_swap_buffers_hook.call(hdc); + g_is_inside_opengl_swap_buffers = true; + + callback_ptr cb; { - g_is_inside_opengl_swap_buffers = true; - - callback_ptr cb; - { - std::shared_lock lock(mgr.m_opengl_swap_buffers_mutex); - cb = mgr.m_opengl_swap_buffers_cb; - } - if (cb) - (*cb)(hdc); - - const BOOL result = mgr.m_opengl_wgl_swap_buffers_hook.call(hdc); - g_is_inside_opengl_swap_buffers = false; - return result; + std::shared_lock lock(mgr.m_opengl_swap_buffers_mutex); + cb = mgr.m_opengl_swap_buffers_cb; } + if (cb) + (*cb)(hdc); - return mgr.m_opengl_wgl_swap_buffers_hook.call(hdc); + const BOOL result = mgr.m_opengl_wgl_swap_buffers_hook.call(hdc); + g_is_inside_opengl_swap_buffers = false; + return result; } BOOL __stdcall HooksManager::opengl_swap_buffers_detour(HDC hdc) { auto& mgr = get(); - if (!g_is_inside_opengl_swap_buffers) + if (g_is_inside_opengl_swap_buffers) + return mgr.m_opengl_swap_buffers_hook.call(hdc); + g_is_inside_opengl_swap_buffers = true; + + callback_ptr cb; { - g_is_inside_opengl_swap_buffers = true; - - callback_ptr cb; - { - std::shared_lock lock(mgr.m_opengl_swap_buffers_mutex); - cb = mgr.m_opengl_swap_buffers_cb; - } - if (cb) - (*cb)(hdc); - - const BOOL result = mgr.m_opengl_swap_buffers_hook.call(hdc); - g_is_inside_opengl_swap_buffers = false; - return result; + std::shared_lock lock(mgr.m_opengl_swap_buffers_mutex); + cb = mgr.m_opengl_swap_buffers_cb; } + if (cb) + (*cb)(hdc); - return mgr.m_opengl_swap_buffers_hook.call(hdc); + const BOOL result = mgr.m_opengl_swap_buffers_hook.call(hdc); + g_is_inside_opengl_swap_buffers = false; + return result; } LRESULT __stdcall HooksManager::wnd_proc_detour(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param) @@ -676,6 +675,56 @@ namespace omath::hooks } return CallWindowProc(original, hwnd, msg, w_param, l_param); } +#endif // _WIN32 + +#ifdef __linux__ + bool HooksManager::hook_opengl() + { + std::unique_lock lock(m_hook_state_mutex); + if (m_is_opengl_hooked) + return true; + + void* glx_swap_buffers = dlsym(RTLD_DEFAULT, "glXSwapBuffers"); + if (!glx_swap_buffers) + return false; + + m_opengl_glx_swap_buffers_hook = safetyhook::create_inline( + glx_swap_buffers, reinterpret_cast(&opengl_glx_swap_buffers_detour)); + + if (!m_opengl_glx_swap_buffers_hook) + return false; + + m_is_opengl_hooked = true; + return true; + } + + void HooksManager::unhook_opengl() + { + std::unique_lock lock(m_hook_state_mutex); + m_opengl_glx_swap_buffers_hook = {}; + m_is_opengl_hooked = false; + } + + void HooksManager::opengl_glx_swap_buffers_detour(Display* display, GLXDrawable drawable) + { + auto& mgr = get(); + callback_ptr cb; + { + std::shared_lock lock(mgr.m_opengl_swap_buffers_mutex); + cb = mgr.m_opengl_swap_buffers_cb; + } + if (cb) + (*cb)(display, drawable); + mgr.m_opengl_glx_swap_buffers_hook.call(display, drawable); + } +#endif // __linux__ + + void HooksManager::set_on_opengl_swap_buffers(opengl_swap_buffers_callback callback) + { + std::unique_lock lock(m_opengl_swap_buffers_mutex); + m_opengl_swap_buffers_cb = + callback ? std::make_shared(std::move(callback)) : nullptr; + } } // namespace omath::hooks #else // !OMATH_ENABLE_HOOKING