Linux renderer detection

This commit is contained in:
Nemirtingas 2019-08-31 20:49:55 +02:00
parent 86f94bc337
commit c27ab3993c
2 changed files with 221 additions and 51 deletions

View file

@ -1,6 +1,10 @@
#include "Renderer_Detector.h" #include "Renderer_Detector.h"
#include "Hook_Manager.h" #include "Hook_Manager.h"
#include <algorithm>
constexpr int max_hook_retries = 500;
#ifdef STEAM_WIN32 #ifdef STEAM_WIN32
#include "DX12_Hook.h" #include "DX12_Hook.h"
#include "DX11_Hook.h" #include "DX11_Hook.h"
@ -8,13 +12,7 @@
#include "DX9_Hook.h" #include "DX9_Hook.h"
#include "OpenGL_Hook.h" #include "OpenGL_Hook.h"
#include "Windows_Hook.h" #include "Windows_Hook.h"
#endif
#include <algorithm>
constexpr int max_hook_retries = 500;
#ifdef STEAM_WIN32
static decltype(&IDXGISwapChain::Present) _IDXGISwapChain_Present = nullptr; static decltype(&IDXGISwapChain::Present) _IDXGISwapChain_Present = nullptr;
static decltype(&IDirect3DDevice9::Present) _IDirect3DDevice9_Present = nullptr; static decltype(&IDirect3DDevice9::Present) _IDirect3DDevice9_Present = nullptr;
static decltype(&IDirect3DDevice9Ex::PresentEx) _IDirect3DDevice9Ex_PresentEx = 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) void Renderer_Detector::create_hook(const char* libname)
{ {
if (!_stricmp(libname, "d3d9.dll")) if (!_stricmp(libname, DX9_Hook::DLL_NAME))
hook_dx9(); hook_dx9();
else if (!_stricmp(libname, "d3d10.dll")) else if (!_stricmp(libname, DX10_Hook::DLL_NAME))
hook_dx10(); hook_dx10();
else if (!_stricmp(libname, "d3d11.dll")) else if (!_stricmp(libname, DX11_Hook::DLL_NAME))
hook_dx11(); hook_dx11();
else if (!_stricmp(libname, "d3d12.dll")) else if (!_stricmp(libname, DX12_Hook::DLL_NAME))
hook_dx12(); hook_dx12();
else if (!_stricmp(libname, "opengl32.dll")) else if (!_stricmp(libname, OpenGL_Hook::DLL_NAME))
hook_opengl(); 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) void Renderer_Detector::find_renderer_proc(Renderer_Detector* _this)
{ {
_this->rendererdetect_hook = new Base_Hook(); _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) void Renderer_Detector::renderer_found(Base_Hook* hook)
{ {
Hook_Manager& hm = Hook_Manager::Inst(); Hook_Manager& hm = Hook_Manager::Inst();
@ -578,7 +553,6 @@ void Renderer_Detector::renderer_found(Base_Hook* hook)
hm.RemoveHook(rendererdetect_hook); hm.RemoveHook(rendererdetect_hook);
destroy_hwnd(); destroy_hwnd();
#ifdef STEAM_WIN32
if (hook == nullptr) // Couldn't hook renderer if (hook == nullptr) // Couldn't hook renderer
{ {
hm.RemoveHook(Windows_Hook::Inst()); hm.RemoveHook(Windows_Hook::Inst());
@ -632,18 +606,6 @@ void Renderer_Detector::renderer_found(Base_Hook* hook)
hm.RemoveHook(h); 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(): Renderer_Detector::Renderer_Detector():
@ -662,6 +624,179 @@ Renderer_Detector::Renderer_Detector():
dummy_hWnd(nullptr) dummy_hWnd(nullptr)
{} {}
#else// defined(__LINUX__)//!STEAM_WIN32
#include "X11_Hook.h"
#include <dlfcn.h>
#include <fstream>
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**, void*>(&(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<std::string> 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() Renderer_Detector::~Renderer_Detector()
{ {
if (_hook_thread != nullptr) if (_hook_thread != nullptr)

View file

@ -5,12 +5,11 @@
#include <thread> #include <thread>
#ifndef NO_OVERLAY #ifndef NO_OVERLAY
#ifdef __WINDOWS__
#ifdef STEAM_WIN32
struct IDXGISwapChain; struct IDXGISwapChain;
struct IDirect3DDevice9; struct IDirect3DDevice9;
struct IDirect3DDevice9Ex; struct IDirect3DDevice9Ex;
#endif
class Renderer_Detector class Renderer_Detector
{ {
@ -64,5 +63,41 @@ public:
static Renderer_Detector& Inst(); 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//NO_OVERLAY
#endif//__INCLUDED_RENDERER_DETECTOR_H__ #endif//__INCLUDED_RENDERER_DETECTOR_H__