From c27ab3993ce20eb56db3048208bd0d5015596f18 Mon Sep 17 00:00:00 2001 From: Nemirtingas Date: Sat, 31 Aug 2019 20:49:55 +0200 Subject: [PATCH] Linux renderer detection --- overlay_experimental/Renderer_Detector.cpp | 231 ++++++++++++++++----- overlay_experimental/Renderer_Detector.h | 41 +++- 2 files changed, 221 insertions(+), 51 deletions(-) diff --git a/overlay_experimental/Renderer_Detector.cpp b/overlay_experimental/Renderer_Detector.cpp index bc74d1a..e15957c 100644 --- a/overlay_experimental/Renderer_Detector.cpp +++ b/overlay_experimental/Renderer_Detector.cpp @@ -1,6 +1,10 @@ #include "Renderer_Detector.h" #include "Hook_Manager.h" +#include + +constexpr int max_hook_retries = 500; + #ifdef STEAM_WIN32 #include "DX12_Hook.h" #include "DX11_Hook.h" @@ -8,13 +12,7 @@ #include "DX9_Hook.h" #include "OpenGL_Hook.h" #include "Windows_Hook.h" -#endif -#include - -constexpr int max_hook_retries = 500; - -#ifdef STEAM_WIN32 static decltype(&IDXGISwapChain::Present) _IDXGISwapChain_Present = nullptr; static decltype(&IDirect3DDevice9::Present) _IDirect3DDevice9_Present = nullptr; static decltype(&IDirect3DDevice9Ex::PresentEx) _IDirect3DDevice9Ex_PresentEx = nullptr; @@ -493,29 +491,18 @@ void Renderer_Detector::hook_opengl() void Renderer_Detector::create_hook(const char* libname) { - if (!_stricmp(libname, "d3d9.dll")) + if (!_stricmp(libname, DX9_Hook::DLL_NAME)) hook_dx9(); - else if (!_stricmp(libname, "d3d10.dll")) + else if (!_stricmp(libname, DX10_Hook::DLL_NAME)) hook_dx10(); - else if (!_stricmp(libname, "d3d11.dll")) + else if (!_stricmp(libname, DX11_Hook::DLL_NAME)) hook_dx11(); - else if (!_stricmp(libname, "d3d12.dll")) + else if (!_stricmp(libname, DX12_Hook::DLL_NAME)) hook_dx12(); - else if (!_stricmp(libname, "opengl32.dll")) + else if (!_stricmp(libname, OpenGL_Hook::DLL_NAME)) hook_opengl(); } -bool Renderer_Detector::stop_retry() -{ - // Retry or not - bool stop = ++_hook_retries >= max_hook_retries; - - if (stop) - renderer_found(nullptr); - - return stop; -} - void Renderer_Detector::find_renderer_proc(Renderer_Detector* _this) { _this->rendererdetect_hook = new Base_Hook(); @@ -547,18 +534,6 @@ void Renderer_Detector::find_renderer_proc(Renderer_Detector* _this) } } -#endif - -void Renderer_Detector::find_renderer() -{ - if (_hook_thread == nullptr) - { -#ifdef STEAM_WIN32 - _hook_thread = new std::thread(&Renderer_Detector::find_renderer_proc, this); -#endif - } -} - void Renderer_Detector::renderer_found(Base_Hook* hook) { Hook_Manager& hm = Hook_Manager::Inst(); @@ -578,7 +553,6 @@ void Renderer_Detector::renderer_found(Base_Hook* hook) hm.RemoveHook(rendererdetect_hook); destroy_hwnd(); -#ifdef STEAM_WIN32 if (hook == nullptr) // Couldn't hook renderer { hm.RemoveHook(Windows_Hook::Inst()); @@ -632,18 +606,6 @@ void Renderer_Detector::renderer_found(Base_Hook* hook) hm.RemoveHook(h); } } -#endif -} - -Renderer_Detector& Renderer_Detector::Inst() -{ - static Renderer_Detector inst; - return inst; -} - -Base_Hook* Renderer_Detector::get_renderer() const -{ - return game_renderer; } Renderer_Detector::Renderer_Detector(): @@ -662,6 +624,179 @@ Renderer_Detector::Renderer_Detector(): dummy_hWnd(nullptr) {} +#else// defined(__LINUX__)//!STEAM_WIN32 +#include "X11_Hook.h" + +#include +#include + +static decltype(glXSwapBuffers)* _glXSwapBuffers = nullptr; + +void Renderer_Detector::MyglXSwapBuffers(Display *dpy, GLXDrawable drawable) +{ + Renderer_Detector& inst = Renderer_Detector::Inst(); + Hook_Manager& hm = Hook_Manager::Inst(); + _glXSwapBuffers(reinterpret_cast<::Display*>(dpy), drawable); + if (!inst.stop_retry()) + { + OpenGLX_Hook::Inst()->start_hook(); + } +} + +void Renderer_Detector::HookglXSwapBuffers(decltype(glXSwapBuffers)* glXSwapBuffers) +{ + _glXSwapBuffers = glXSwapBuffers; + + rendererdetect_hook->BeginHook(); + + rendererdetect_hook->HookFuncs( + std::pair(&(void*&)_glXSwapBuffers, (void*)MyglXSwapBuffers) + ); + + rendererdetect_hook->EndHook(); +} + +void Renderer_Detector::hook_openglx(const char* libname) +{ + if (!_oglx_hooked && !_renderer_found) + { + void* library = dlopen(libname, RTLD_NOW); + decltype(glXSwapBuffers)* glXSwapBuffers = nullptr; + if (library != nullptr) + { + glXSwapBuffers = (decltype(glXSwapBuffers))dlsym(library, "glXSwapBuffers"); + } + if (glXSwapBuffers != nullptr) + { + PRINT_DEBUG("Hooked glXMakeCurrent to detect OpenGLX\n"); + + _oglx_hooked = true; + auto h = OpenGLX_Hook::Inst(); + h->loadFunctions(glXSwapBuffers); + Hook_Manager::Inst().AddHook(h); + HookglXSwapBuffers(glXSwapBuffers); + } + else + { + PRINT_DEBUG("Failed to Hook glXMakeCurrent to detect OpenGLX\n"); + } + } +} + +void Renderer_Detector::create_hook(const char* libname) +{ + if (strcasestr(libname, OpenGLX_Hook::DLL_NAME) != nullptr) + hook_openglx(libname); +} + +void Renderer_Detector::find_renderer_proc(Renderer_Detector* _this) +{ + _this->rendererdetect_hook = new Base_Hook(); + Hook_Manager& hm = Hook_Manager::Inst(); + hm.AddHook(_this->rendererdetect_hook); + + + std::vector const libraries = { "libGLX.so" }; + + while (!_this->_renderer_found && !_this->stop_retry()) + { + std::ifstream flibrary("/proc/self/maps"); + std::string line; + while( std::getline(flibrary, line) ) + { + std::for_each(libraries.begin(), libraries.end(), [&line, &_this]( std::string const& library ) + { + if( std::search(line.begin(), line.end(), library.begin(), library.end()) != line.end() ) + { + _this->create_hook(line.substr(line.find('/')).c_str()); + } + }); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} + +Renderer_Detector::Renderer_Detector(): + _hook_thread(nullptr), + _hook_retries(0), + _renderer_found(false), + _oglx_hooked(false), + rendererdetect_hook(nullptr), + game_renderer(nullptr) +{} + +void Renderer_Detector::renderer_found(Base_Hook* hook) +{ + Hook_Manager& hm = Hook_Manager::Inst(); + + _renderer_found = true; + game_renderer = hook; + + if (hook == nullptr) + PRINT_DEBUG("We found a renderer but couldn't hook it, aborting overlay hook.\n"); + else + PRINT_DEBUG("Hooked renderer in %d/%d tries\n", _hook_retries, max_hook_retries); + + _hook_thread->join(); + delete _hook_thread; + _hook_thread = nullptr; + + hm.RemoveHook(rendererdetect_hook); + + if (hook == nullptr) // Couldn't hook renderer + { + hm.RemoveHook(X11_Hook::Inst()); + } + else + { + hm.AddHook(X11_Hook::Inst()); + } + if (_oglx_hooked) + { + auto h = OpenGLX_Hook::Inst(); + if (h != hook) + { + _oglx_hooked = false; + hm.RemoveHook(h); + } + } +} + +#endif + +bool Renderer_Detector::stop_retry() +{ + // Retry or not + bool stop = ++_hook_retries >= max_hook_retries; + + if (stop) + { + renderer_found(nullptr); + } + + return stop; +} + +void Renderer_Detector::find_renderer() +{ + if (_hook_thread == nullptr) + { + _hook_thread = new std::thread(&Renderer_Detector::find_renderer_proc, this); + } +} + +Renderer_Detector& Renderer_Detector::Inst() +{ + static Renderer_Detector inst; + return inst; +} + +Base_Hook* Renderer_Detector::get_renderer() const +{ + return game_renderer; +} + Renderer_Detector::~Renderer_Detector() { if (_hook_thread != nullptr) @@ -670,4 +805,4 @@ Renderer_Detector::~Renderer_Detector() _hook_thread->join(); delete _hook_thread; } -} \ No newline at end of file +} diff --git a/overlay_experimental/Renderer_Detector.h b/overlay_experimental/Renderer_Detector.h index 04f20b2..a7ba624 100644 --- a/overlay_experimental/Renderer_Detector.h +++ b/overlay_experimental/Renderer_Detector.h @@ -5,12 +5,11 @@ #include #ifndef NO_OVERLAY +#ifdef __WINDOWS__ -#ifdef STEAM_WIN32 struct IDXGISwapChain; struct IDirect3DDevice9; struct IDirect3DDevice9Ex; -#endif class Renderer_Detector { @@ -64,5 +63,41 @@ public: static Renderer_Detector& Inst(); }; +#elif defined __LINUX__ +#include "OpenGLX_Hook.h" + +class Renderer_Detector +{ + // Variables + std::thread* _hook_thread; + unsigned int _hook_retries; + bool _oglx_hooked; + bool _renderer_found; // Is the renderer hooked ? + Base_Hook* rendererdetect_hook; + Base_Hook* game_renderer; + + // Functions + Renderer_Detector(); + ~Renderer_Detector(); + + static void MyglXSwapBuffers(Display *dpy, GLXDrawable drawable); + + void HookglXSwapBuffers(decltype(glXSwapBuffers)* glXSwapBuffers); + + void hook_openglx(const char* libname); + + void create_hook(const char* libname); + bool stop_retry(); + + static void find_renderer_proc(Renderer_Detector* _this); + +public: + void find_renderer(); + void renderer_found(Base_Hook* hook); + Base_Hook* get_renderer() const; + static Renderer_Detector& Inst(); +}; + +#endif//__WINDOWS__ #endif//NO_OVERLAY -#endif//__INCLUDED_RENDERER_DETECTOR_H__ \ No newline at end of file +#endif//__INCLUDED_RENDERER_DETECTOR_H__