Compare commits

..

No commits in common. "c9a102ee302f1cb95bf8fe2d999bf2045ba78476" and "97a1ff5186f6069b57086ab0e6e9512f69fa2bbf" have entirely different histories.

11 changed files with 461 additions and 389 deletions

View File

@ -26,38 +26,33 @@
#include "System/System.h" #include "System/System.h"
#include "System/Library.h" #include "System/Library.h"
#include "System/ScopedLock.hpp" #include "System/ScopedLock.hpp"
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) \ #if defined(WIN64) || defined(_WIN64) || defined(__MINGW64__) \
|| defined(WIN32) || defined(_WIN32) || defined(__MINGW32__) || defined(WIN32) || defined(_WIN32) || defined(__MINGW32__)
#define RENDERERDETECTOR_OS_WINDOWS #define RENDERERDETECTOR_OS_WINDOWS
#include "windows/DX12_Hook.h"
#include "windows/DX11_Hook.h"
#include "windows/DX10_Hook.h"
#include "windows/DX9_Hook.h"
#include "windows/OpenGL_Hook.h"
#include "windows/Vulkan_Hook.h"
#include "windows/DirectX_VTables.h"
#include <random>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif
#elif defined(__linux__) || defined(linux) #elif defined(__linux__) || defined(linux)
#define RENDERERDETECTOR_OS_LINUX #define RENDERERDETECTOR_OS_LINUX
#include "linux/OpenGLX_Hook.h"
#elif defined(__APPLE__) #elif defined(__APPLE__)
#define RENDERERDETECTOR_OS_APPLE #define RENDERERDETECTOR_OS_APPLE
#endif
#include "macosx/OpenGL_Hook.h" #ifdef RENDERERDETECTOR_OS_WINDOWS
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#include "windows/DX12_Hook.h"
#include "windows/DX11_Hook.h"
#include "windows/DX10_Hook.h"
#include "windows/DX9_Hook.h"
#include "windows/OpenGL_Hook.h"
#include "windows/Vulkan_Hook.h"
#include "windows/DirectX_VTables.h"
#include <random>
#ifdef GetModuleHandle
#undef GetModuleHandle
#endif #endif
class Renderer_Detector class Renderer_Detector
@ -73,60 +68,27 @@ public:
return instance; return instance;
} }
#if defined(RENDERERDETECTOR_OS_WINDOWS) static void deleteInst()
#define RENDERER_HOOKS { OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl },\ {
{ Vulkan_Hook::DLL_NAME, &Renderer_Detector::hook_vulkan },\ if (instance != nullptr)
{ DX12_Hook::DLL_NAME, &Renderer_Detector::hook_dx12 },\ {
{ DX11_Hook::DLL_NAME, &Renderer_Detector::hook_dx11 },\ delete instance;
{ DX10_Hook::DLL_NAME, &Renderer_Detector::hook_dx10 },\ instance = nullptr;
{ DX9_Hook::DLL_NAME, &Renderer_Detector::hook_dx9 }, }
}
~Renderer_Detector() ~Renderer_Detector()
{ {
stop_detection();
delete dx9_hook; delete dx9_hook;
delete dx10_hook; delete dx10_hook;
delete dx11_hook; delete dx11_hook;
delete dx12_hook; delete dx12_hook;
delete opengl_hook; delete opengl_hook;
delete vulkan_hook; delete vulkan_hook;
instance = nullptr;
} }
private: private:
Renderer_Detector():
decltype(&IDXGISwapChain::Present) IDXGISwapChainPresent;
decltype(&IDXGISwapChain1::Present1) IDXGISwapChainPresent1;
decltype(&IDirect3DDevice9::Present) IDirect3DDevice9Present;
decltype(&IDirect3DDevice9Ex::PresentEx) IDirect3DDevice9ExPresentEx;
decltype(&IDirect3DSwapChain9::Present) IDirect3DSwapChain9Present;
decltype(::SwapBuffers)* wglSwapBuffers;
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
bool dxgi_hooked;
bool dxgi1_2_hooked;
bool dx12_hooked;
bool dx11_hooked;
bool dx10_hooked;
bool dx9_hooked;
bool opengl_hooked;
bool vulkan_hooked;
DX12_Hook* dx12_hook;
DX11_Hook* dx11_hook;
DX10_Hook* dx10_hook;
DX9_Hook* dx9_hook;
OpenGL_Hook* opengl_hook;
Vulkan_Hook* vulkan_hook;
HWND dummyWindow = nullptr;
std::wstring _WindowClassName;
std::string _SystemDir;
ATOM atom = 0;
Renderer_Detector() :
dxgi_hooked(false), dxgi_hooked(false),
dxgi1_2_hooked(false), dxgi1_2_hooked(false),
dx12_hooked(false), dx12_hooked(false),
@ -143,8 +105,7 @@ private:
opengl_hook(nullptr), opengl_hook(nullptr),
vulkan_hook(nullptr), vulkan_hook(nullptr),
detection_done(false), detection_done(false),
detection_count(0), force_done(false)
detection_cancelled(false)
{ {
std::wstring tmp(4096, L'\0'); std::wstring tmp(4096, L'\0');
tmp.resize(GetSystemDirectoryW(&tmp[0], tmp.size())); tmp.resize(GetSystemDirectoryW(&tmp[0], tmp.size()));
@ -162,6 +123,44 @@ private:
_WindowClassName[i] = random_str[dis(gen)]; _WindowClassName[i] = random_str[dis(gen)];
} }
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
decltype(&IDXGISwapChain::Present) IDXGISwapChainPresent;
decltype(&IDXGISwapChain1::Present1) IDXGISwapChainPresent1;
decltype(&IDirect3DDevice9::Present) IDirect3DDevice9Present;
decltype(&IDirect3DDevice9Ex::PresentEx) IDirect3DDevice9ExPresentEx;
decltype(&IDirect3DSwapChain9::Present) IDirect3DSwapChain9Present;
decltype(::SwapBuffers)* wglSwapBuffers;
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
bool dxgi_hooked;
bool dxgi1_2_hooked;
bool dx12_hooked;
bool dx11_hooked;
bool dx10_hooked;
bool dx9_hooked;
bool opengl_hooked;
bool vulkan_hooked;
Base_Hook detection_hooks;
ingame_overlay::Renderer_Hook* renderer_hook;
DX12_Hook* dx12_hook;
DX11_Hook* dx11_hook;
DX10_Hook* dx10_hook;
DX9_Hook* dx9_hook;
OpenGL_Hook* opengl_hook;
Vulkan_Hook* vulkan_hook;
bool detection_done, force_done;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
HWND dummyWindow = nullptr;
std::wstring _WindowClassName;
std::string _SystemDir;
ATOM atom = 0;
std::string FindPreferedModulePath(std::string const& name) std::string FindPreferedModulePath(std::string const& name)
{ {
std::string res; std::string res;
@ -401,7 +400,7 @@ private:
return res; return res;
inst->HookDetected(inst->vulkan_hook); inst->HookDetected(inst->vulkan_hook);
return res; return res;
} }
@ -446,20 +445,20 @@ private:
void*& pfnSwapChainPresent) void*& pfnSwapChainPresent)
{ {
void** vTable = *reinterpret_cast<void***>(pDevice); void** vTable = *reinterpret_cast<void***>(pDevice);
pfnPresent = vTable[(int)IDirect3DDevice9VTable::Present]; pfnPresent = vTable[(int)IDirect3DDevice9VTable::Present];
pfnReset = vTable[(int)IDirect3DDevice9VTable::Reset]; pfnReset = vTable[(int)IDirect3DDevice9VTable::Reset];
(void*&)IDirect3DDevice9Present = vTable[(int)IDirect3DDevice9VTable::Present]; (void*&)IDirect3DDevice9Present = vTable[(int)IDirect3DDevice9VTable::Present];
detection_hooks.BeginHook(); detection_hooks.BeginHook();
detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DDevice9Present, (void*)&MyDX9Present }); detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DDevice9Present, (void*)&MyDX9Present });
detection_hooks.EndHook(); detection_hooks.EndHook();
if (ex) if (ex)
{ {
pfnPresentEx = vTable[(int)IDirect3DDevice9VTable::PresentEx]; pfnPresentEx = vTable[(int)IDirect3DDevice9VTable::PresentEx];
(void*&)IDirect3DDevice9ExPresentEx = vTable[(int)IDirect3DDevice9VTable::PresentEx]; (void*&)IDirect3DDevice9ExPresentEx = vTable[(int)IDirect3DDevice9VTable::PresentEx];
detection_hooks.BeginHook(); detection_hooks.BeginHook();
detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DDevice9ExPresentEx, (void*)&MyDX9PresentEx }); detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DDevice9ExPresentEx, (void*)&MyDX9PresentEx });
detection_hooks.EndHook(); detection_hooks.EndHook();
@ -469,13 +468,13 @@ private:
pfnPresentEx = nullptr; pfnPresentEx = nullptr;
IDirect3DDevice9ExPresentEx = nullptr; IDirect3DDevice9ExPresentEx = nullptr;
} }
if (pSwapChain != nullptr) if (pSwapChain != nullptr)
{ {
vTable = *reinterpret_cast<void***>(pSwapChain); vTable = *reinterpret_cast<void***>(pSwapChain);
pfnSwapChainPresent = vTable[(int)IDirect3DSwapChain9VTable::Present]; pfnSwapChainPresent = vTable[(int)IDirect3DSwapChain9VTable::Present];
(void*&)IDirect3DSwapChain9Present = vTable[(int)IDirect3DSwapChain9VTable::Present]; (void*&)IDirect3DSwapChain9Present = vTable[(int)IDirect3DSwapChain9VTable::Present];
detection_hooks.BeginHook(); detection_hooks.BeginHook();
detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DSwapChain9Present, (void*)&MyDX9SwapChainPresent }); detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&IDirect3DSwapChain9Present, (void*)&MyDX9SwapChainPresent });
detection_hooks.EndHook(); detection_hooks.EndHook();
@ -536,7 +535,7 @@ private:
Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D); Direct3DCreate9Ex(D3D_SDK_VERSION, &pD3D);
pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, NULL, reinterpret_cast<IDirect3DDevice9Ex**>(&pDevice)); pD3D->CreateDeviceEx(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, NULL, D3DCREATE_HARDWARE_VERTEXPROCESSING, &params, NULL, reinterpret_cast<IDirect3DDevice9Ex**>(&pDevice));
} }
if (pDevice == nullptr) if (pDevice == nullptr)
{ {
Direct3DCreate9Ex = nullptr; Direct3DCreate9Ex = nullptr;
@ -552,7 +551,7 @@ private:
if (pDevice != nullptr) if (pDevice != nullptr)
{ {
SPDLOG_INFO("Hooked D3D9::Present to detect DX Version"); SPDLOG_INFO("Hooked D3D9::Present to detect DX Version");
dx9_hooked = true; dx9_hooked = true;
pDevice->GetSwapChain(0, &pSwapChain); pDevice->GetSwapChain(0, &pSwapChain);
@ -748,7 +747,7 @@ private:
if (pDXGIFactory) pDXGIFactory->Release(); if (pDXGIFactory) pDXGIFactory->Release();
} }
} }
if (pDevice != nullptr && pSwapChain != nullptr) if (pDevice != nullptr && pSwapChain != nullptr)
{ {
version = 1; version = 1;
@ -983,8 +982,7 @@ private:
phyDevices.resize(count); phyDevices.resize(count);
vkEnumeratePhysicalDevices(instance, &count, phyDevices.data()); vkEnumeratePhysicalDevices(instance, &count, phyDevices.data());
[&]() [&]() {
{// Lambda for nested for break.
VkPhysicalDeviceProperties props{}; VkPhysicalDeviceProperties props{};
std::vector<VkExtensionProperties> ext_props; std::vector<VkExtensionProperties> ext_props;
@ -1007,7 +1005,7 @@ private:
const char* str = "VK_KHR_swapchain"; const char* str = "VK_KHR_swapchain";
create_info.ppEnabledExtensionNames = &str; create_info.ppEnabledExtensionNames = &str;
vkCreateDevice(device, &create_info, nullptr, &pDevice); vkCreateDevice(device, &create_info, nullptr, &pDevice);
if (pDevice != nullptr) if(pDevice != nullptr)
return; return;
} }
} }
@ -1029,11 +1027,11 @@ private:
SPDLOG_INFO("Hooked vkQueuePresentKHR to detect Vulkan"); SPDLOG_INFO("Hooked vkQueuePresentKHR to detect Vulkan");
vulkan_hooked = true; vulkan_hooked = true;
vulkan_hook = Vulkan_Hook::Inst(); vulkan_hook = Vulkan_Hook::Inst();
vulkan_hook->LibraryName = library_path; vulkan_hook->LibraryName = library_path;
vulkan_hook->LoadFunctions(vkQueuePresentKHR); vulkan_hook->LoadFunctions(vkQueuePresentKHR);
HookvkQueuePresentKHR(vkQueuePresentKHR); HookvkQueuePresentKHR(vkQueuePresentKHR);
} }
else else
@ -1043,71 +1041,155 @@ private:
} }
} }
bool EnterDetection() public:
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{ {
return CreateHWND() != nullptr; std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
if (!detection_lock.try_lock_for(timeout))
return nullptr;
{
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done)
{
if (renderer_hook != nullptr || force_done)
return renderer_hook;
detection_done = false;
}
if (CreateHWND() == nullptr)
{
return nullptr;
}
}
SPDLOG_TRACE("Started renderer detection.");
std::pair<std::string, void(Renderer_Detector::*)(std::string const&)> libraries[]{
{OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl},
{Vulkan_Hook::DLL_NAME, &Renderer_Detector::hook_vulkan},
{ DX12_Hook::DLL_NAME, &Renderer_Detector::hook_dx12 },
{ DX11_Hook::DLL_NAME, &Renderer_Detector::hook_dx11 },
{ DX10_Hook::DLL_NAME, &Renderer_Detector::hook_dx10 },
{ DX9_Hook::DLL_NAME, &Renderer_Detector::hook_dx9 },
};
std::string name;
auto start_time = std::chrono::steady_clock::now();
do
{
std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_done)
break;
for (auto const& library : libraries)
{
void* lib_handle = System::Library::GetLibraryHandle(library.first.c_str());
if (lib_handle != nullptr)
{
std::lock_guard<std::mutex> lk(renderer_mutex);
name = FindPreferedModulePath(library.first);
(this->*library.second)(name);
}
}
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout));
{
std::lock_guard<std::mutex> lk(renderer_mutex);
DestroyHWND();
detection_done = true;
detection_hooks.UnhookAll();
dxgi_hooked = false;
dxgi1_2_hooked = false;
dx12_hooked = false;
dx11_hooked = false;
dx10_hooked = false;
dx9_hooked = false;
opengl_hooked = false;
vulkan_hooked = false;
delete dx9_hook ; dx9_hook = nullptr;
delete dx10_hook ; dx10_hook = nullptr;
delete dx11_hook ; dx11_hook = nullptr;
delete dx12_hook ; dx12_hook = nullptr;
delete opengl_hook; opengl_hook = nullptr;
delete vulkan_hook; vulkan_hook = nullptr;
}
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook;
} }
void ExitDetection() void stop_detection()
{ {
DestroyHWND(); {
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true; detection_done = true;
detection_hooks.UnhookAll(); force_done = true;
}
dxgi_hooked = false; stop_detection_cv.notify_all();
dxgi1_2_hooked = false;
dx12_hooked = false;
dx11_hooked = false;
dx10_hooked = false;
dx9_hooked = false;
opengl_hooked = false;
vulkan_hooked = false;
delete dx9_hook ; dx9_hook = nullptr;
delete dx10_hook ; dx10_hook = nullptr;
delete dx11_hook ; dx11_hook = nullptr;
delete dx12_hook ; dx12_hook = nullptr;
delete opengl_hook; opengl_hook = nullptr;
delete vulkan_hook; vulkan_hook = nullptr;
} }
};
Renderer_Detector* Renderer_Detector::instance = nullptr;
#elif defined(RENDERERDETECTOR_OS_LINUX) #elif defined(RENDERERDETECTOR_OS_LINUX)
#define RENDERER_HOOKS { OpenGLX_Hook::DLL_NAME, &Renderer_Detector::hook_openglx }, #define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#include "linux/OpenGLX_Hook.h"
class Renderer_Detector
{
static Renderer_Detector* instance;
public:
static Renderer_Detector* Inst()
{
if (instance == nullptr)
{
instance = new Renderer_Detector;
}
return instance;
}
~Renderer_Detector() ~Renderer_Detector()
{ {
stop_detection();
delete openglx_hook; delete openglx_hook;
//delete vulkan_hook; //delete vulkan_hook;
instance = nullptr;
} }
private: private:
decltype(::glXSwapBuffers)* glXSwapBuffers;
bool openglx_hooked;
//bool vulkan_hooked;
OpenGLX_Hook* openglx_hook;
//Vulkan_Hook* vulkan_hook;
Renderer_Detector() : Renderer_Detector() :
openglx_hooked(false), openglx_hooked(false),
renderer_hook(nullptr), renderer_hook(nullptr),
openglx_hook(nullptr), openglx_hook(nullptr),
//vulkan_hook(nullptr), //vulkan_hook(nullptr),
detection_done(false), detection_done(false)
detection_count(0),
detection_cancelled(false)
{} {}
std::string FindPreferedModulePath(std::string const& name) std::timed_mutex detector_mutex;
{ std::mutex renderer_mutex;
return name;
} Base_Hook detection_hooks;
decltype(::glXSwapBuffers)* glXSwapBuffers;
bool openglx_hooked;
//bool vulkan_hooked;
ingame_overlay::Renderer_Hook* renderer_hook;
OpenGLX_Hook* openglx_hook;
bool detection_done;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
static void MyglXSwapBuffers(Display* dpy, GLXDrawable drawable) static void MyglXSwapBuffers(Display* dpy, GLXDrawable drawable)
{ {
@ -1166,273 +1248,269 @@ private:
} }
} }
bool EnterDetection()
{
return true;
}
void ExitDetection()
{
detection_done = true;
detection_hooks.UnhookAll();
openglx_hooked = false;
//vulkan_hooked = false;
delete openglx_hook; openglx_hook = nullptr;
//delete vulkan_hook; vulkan_hook = nullptr;
}
#elif defined(RENDERERDETECTOR_OS_APPLE)
#define RENDERER_HOOKS { OpenGL_Hook::DLL_NAME, & Renderer_Detector::hook_opengl },
~Renderer_Detector()
{
stop_detection();
delete opengl_hook;
instance = nullptr;
}
private:
decltype(::CGLFlushDrawable)* CGLFlushDrawable;
bool opengl_hooked;
//bool metal_hooked;
OpenGL_Hook* opengl_hook;
//Metal_Hook* metal_hook;
Renderer_Detector() :
opengl_hooked(false),
renderer_hook(nullptr),
opengl_hook(nullptr),
detection_done(false),
detection_count(0),
detection_cancelled(false)
{}
std::string FindPreferedModulePath(std::string const& name)
{
return name;
}
static int64_t MyCGLFlushDrawable(CGLDrawable_t* glDrawable)
{
auto inst = Inst();
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
int64_t res = inst->CGLFlushDrawable(glDrawable);
if (gladLoaderLoadGL() >= GLAD_MAKE_VERSION(2, 0))
{
inst->detection_hooks.UnhookAll();
inst->renderer_hook = static_cast<ingame_overlay::Renderer_Hook*>(Inst()->opengl_hook);
inst->opengl_hook = nullptr;
inst->detection_done = true;
}
return res;
}
void HookglFlushDrawable(decltype(::CGLFlushDrawable)* _CGLFlushDrawable)
{
CGLFlushDrawable = _CGLFlushDrawable;
detection_hooks.BeginHook();
detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&CGLFlushDrawable, (void*)&MyCGLFlushDrawable });
detection_hooks.EndHook();
}
void hook_opengl(std::string const& library_path)
{
if (!opengl_hooked)
{
System::Library::Library libOpenGL;
if (!libOpenGL.OpenLibrary(library_path, false))
{
SPDLOG_WARN("Failed to load {} to detect OpenGL", library_path);
return;
}
auto CGLFlushDrawable = libOpenGL.GetSymbol<decltype(::CGLFlushDrawable)>("CGLFlushDrawable");
if (CGLFlushDrawable != nullptr)
{
SPDLOG_INFO("Hooked CGLFlushDrawable to detect OpenGL");
opengl_hooked = true;
opengl_hook = OpenGL_Hook::Inst();
opengl_hook->LibraryName = library_path;
opengl_hook->LoadFunctions(CGLFlushDrawable);
HookglFlushDrawable(CGLFlushDrawable);
}
else
{
SPDLOG_WARN("Failed to Hook CGLFlushDrawable to detect OpenGL");
}
}
}
bool EnterDetection()
{
return true;
}
void ExitDetection()
{
detection_done = true;
detection_hooks.UnhookAll();
opengl_hooked = false;
//metal_hooked = false;
delete opengl_hook; opengl_hook = nullptr;
//delete metal_hook; metal_hook = nullptr;
}
#endif
private:
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
Base_Hook detection_hooks;
ingame_overlay::Renderer_Hook* renderer_hook;
bool detection_done;
uint32_t detection_count;
bool detection_cancelled;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
public: public:
std::future<ingame_overlay::Renderer_Hook*> detect_renderer(std::chrono::milliseconds timeout) ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{ {
std::lock_guard<std::mutex> lk(stop_detection_mutex); std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGLX_Hook::DLL_NAME, &Renderer_Detector::hook_openglx},
};
if (detection_count == 0) std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
{// If we have no detections in progress, restart detection.
detection_cancelled = false; if (!detection_lock.try_lock_for(timeout))
return nullptr;
{
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done)
{
if (renderer_hook != nullptr || force_done)
return renderer_hook;
detection_done = false;
}
} }
++detection_count; SPDLOG_TRACE("Started renderer detection.");
return std::async(std::launch::async, [this, timeout]() -> ingame_overlay::Renderer_Hook* auto start_time = std::chrono::steady_clock::now();
do
{ {
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock); std::unique_lock<std::mutex> lck(stop_detection_mutex);
constexpr std::chrono::milliseconds infinite_timeout{ -1 }; if (detection_done)
break;
if (!detection_lock.try_lock_for(timeout))
return nullptr;
bool cancel = false; for (auto const& library : libraries)
{ {
System::scoped_lock lk(renderer_mutex, stop_detection_mutex); void* lib_handle = System::Library::GetLibraryHandle(library.first);
if (lib_handle != nullptr)
if (!detection_cancelled)
{ {
if (detection_done) std::lock_guard<std::mutex> lk(renderer_mutex);
{ std::string lib_path = System::Library::GetLibraryPath(lib_handle);
if (renderer_hook == nullptr) (this->*library.second)(lib_path);
{// Renderer detection was run but we didn't find it, restart the detection
detection_done = false;
}
else
{// Renderer already detected, cancel detection and return the renderer.
cancel = true;
}
}
if (!EnterDetection())
cancel = true;
}
else
{// Detection was cancelled, cancel this detection
cancel = true;
} }
} }
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout));
if (cancel) {
{ std::lock_guard<std::mutex> lk(renderer_mutex);
--detection_count;
stop_detection_cv.notify_all(); detection_done = true;
return renderer_hook; detection_hooks.UnhookAll();
}
SPDLOG_TRACE("Started renderer detection."); openglx_hooked = false;
std::pair<std::string, void(Renderer_Detector::*)(std::string const&)> libraries[]{ delete openglx_hook; openglx_hook = nullptr;
RENDERER_HOOKS //delete vulkan_hook; vulkan_hook = nullptr;
}; }
std::string name;
auto start_time = std::chrono::steady_clock::now(); SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
do
{
std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_cancelled || detection_done)
break;
for (auto const& library : libraries) return renderer_hook;
{
std::string lib_path = FindPreferedModulePath(library.first);
if (!lib_path.empty())
{
void* lib_handle = System::Library::GetLibraryHandle(lib_path.c_str());
if (lib_handle != nullptr)
{
std::lock_guard<std::mutex> lk(renderer_mutex);
(this->*library.second)(System::Library::GetLibraryPath(lib_handle));
}
}
}
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (timeout == infinite_timeout || (std::chrono::steady_clock::now() - start_time) <= timeout);
{
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
ExitDetection();
--detection_count;
}
stop_detection_cv.notify_all();
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook;
});
} }
void stop_detection() void stop_detection()
{ {
{
std::lock_guard<std::mutex> lk(stop_detection_mutex);
if (detection_count == 0)
return;
}
{ {
System::scoped_lock lk(renderer_mutex, stop_detection_mutex); System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_cancelled = true; detection_done = true;
force_done = true;
} }
stop_detection_cv.notify_all(); stop_detection_cv.notify_all();
{
std::unique_lock<std::mutex> lk(stop_detection_mutex);
stop_detection_cv.wait(lk, [&]() { return detection_count == 0; });
}
} }
}; };
Renderer_Detector* Renderer_Detector::instance = nullptr; Renderer_Detector* Renderer_Detector::instance = nullptr;
#elif defined(RENDERERDETECTOR_OS_APPLE)
#include "macosx/OpenGL_Hook.h"
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
class Renderer_Detector
{
static Renderer_Detector* instance;
public:
static Renderer_Detector* Inst()
{
if (instance == nullptr)
{
instance = new Renderer_Detector;
}
return instance;
}
~Renderer_Detector()
{
delete opengl_hook;
}
private:
Renderer_Detector():
opengl_hooked(false),
renderer_hook(nullptr),
opengl_hook(nullptr),
detection_done(false)
{}
std::timed_mutex detector_mutex;
std::mutex renderer_mutex;
Base_Hook detection_hooks;
decltype(::CGLFlushDrawable)* CGLFlushDrawable;
bool opengl_hooked;
ingame_overlay::Renderer_Hook* renderer_hook;
OpenGL_Hook* opengl_hook;
bool detection_done;
std::condition_variable stop_detection_cv;
std::mutex stop_detection_mutex;
static int64_t MyCGLFlushDrawable(CGLDrawable_t* glDrawable)
{
auto inst = Inst();
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
int64_t res = inst->CGLFlushDrawable(glDrawable);
if (gladLoaderLoadGL() >= GLAD_MAKE_VERSION(2, 0))
{
inst->detection_hooks.UnhookAll();
inst->renderer_hook = static_cast<ingame_overlay::Renderer_Hook*>(Inst()->opengl_hook);
inst->opengl_hook = nullptr;
inst->detection_done = true;
}
return res;
}
void HookglFlushDrawable(decltype(::CGLFlushDrawable)* _CGLFlushDrawable)
{
CGLFlushDrawable = _CGLFlushDrawable;
detection_hooks.BeginHook();
detection_hooks.HookFunc(std::pair<void**, void*>{ (void**)&CGLFlushDrawable, (void*)&MyCGLFlushDrawable });
detection_hooks.EndHook();
}
void hook_opengl(std::string const& library_path)
{
if (!opengl_hooked)
{
System::Library::Library libOpenGL;
if (!libOpenGL.OpenLibrary(library_path, false))
{
SPDLOG_WARN("Failed to load {} to detect OpenGL", library_path);
return;
}
auto CGLFlushDrawable = libOpenGL.GetSymbol<decltype(::CGLFlushDrawable)>("CGLFlushDrawable");
if (CGLFlushDrawable != nullptr)
{
SPDLOG_INFO("Hooked CGLFlushDrawable to detect OpenGL");
opengl_hooked = true;
opengl_hook = OpenGL_Hook::Inst();
opengl_hook->LibraryName = library_path;
opengl_hook->LoadFunctions(CGLFlushDrawable);
HookglFlushDrawable(CGLFlushDrawable);
}
else
{
SPDLOG_WARN("Failed to Hook CGLFlushDrawable to detect OpenGL");
}
}
}
public:
ingame_overlay::Renderer_Hook* detect_renderer(std::chrono::milliseconds timeout)
{
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)> libraries[]{
std::pair<const char*, void(Renderer_Detector::*)(std::string const&)>{OpenGL_Hook::DLL_NAME, &Renderer_Detector::hook_opengl}
};
std::unique_lock<std::timed_mutex> detection_lock(detector_mutex, std::defer_lock);
if (!detection_lock.try_lock_for(timeout))
return nullptr;
{
std::lock_guard<std::mutex> lk(renderer_mutex);
if (detection_done)
{
if (renderer_hook != nullptr || force_done)
return renderer_hook;
detection_done = false;
}
}
SPDLOG_TRACE("Started renderer detection.");
auto start_time = std::chrono::steady_clock::now();
do
{
std::unique_lock<std::mutex> lck(stop_detection_mutex);
if (detection_done)
break;
for (auto const& library : libraries)
{
void* lib_handle = System::Library::GetLibraryHandle(library.first);
if (lib_handle != nullptr)
{
std::lock_guard<std::mutex> lk(renderer_mutex);
std::string lib_path = System::Library::GetLibraryPath(lib_handle);
(this->*library.second)(lib_path);
}
}
stop_detection_cv.wait_for(lck, std::chrono::milliseconds{ 100 });
} while (!detection_done && (timeout.count() == -1 || (std::chrono::steady_clock::now() - start_time) <= timeout));
{
std::lock_guard<std::mutex> lk(renderer_mutex);
detection_done = true;
detection_hooks.UnhookAll();
opengl_hooked = false;
delete opengl_hook; opengl_hook = nullptr;
//delete vulkan_hook; vulkan_hook = nullptr;
}
SPDLOG_TRACE("Renderer detection done {}.", (void*)renderer_hook);
return renderer_hook;
}
void stop_detection()
{
{
System::scoped_lock lk(renderer_mutex, stop_detection_mutex);
detection_done = true;
force_done = true;
}
stop_detection_cv.notify_all();
}
};
Renderer_Detector* Renderer_Detector::instance = nullptr;
#endif
namespace ingame_overlay { namespace ingame_overlay {
std::future<ingame_overlay::Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout) std::future<ingame_overlay::Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout)
{ {
return Renderer_Detector::Inst()->detect_renderer(timeout); return std::async(std::launch::async, &Renderer_Detector::detect_renderer, Renderer_Detector::Inst(), timeout);
} }
void StopRendererDetection() void StopRendererDetection()
@ -1440,9 +1518,9 @@ void StopRendererDetection()
Renderer_Detector::Inst()->stop_detection(); Renderer_Detector::Inst()->stop_detection();
} }
void FreeDetector() void FreeRendererDetection()
{ {
delete Renderer_Detector::Inst(); Renderer_Detector::deleteInst();
} }
} }

View File

@ -31,6 +31,5 @@ namespace ingame_overlay {
std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 }); std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 });
void StopRendererDetection(); void StopRendererDetection();
void FreeDetector(); void FreeRendererDetection();
} }

View File

@ -39,8 +39,7 @@ class Renderer_Hook
public: public:
Renderer_Hook(): Renderer_Hook():
OverlayProc(&DefaultOverlayProc), OverlayProc(&DefaultOverlayProc),
OverlayHookReady(&DefaultOverlayHookReady), OverlayHookReady(&DefaultOverlayHookReady)
ImGuiFontAtlas(nullptr)
{} {}
static void DefaultOverlayProc() {} static void DefaultOverlayProc() {}
@ -48,7 +47,6 @@ public:
std::function<void()> OverlayProc; std::function<void()> OverlayProc;
std::function<void(bool)> OverlayHookReady; std::function<void(bool)> OverlayHookReady;
void *ImGuiFontAtlas;
virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ToggleKey> toggle_keys) = 0; virtual bool StartHook(std::function<bool(bool)> key_combination_callback, std::set<ToggleKey> toggle_keys) = 0;
virtual bool IsStarted() = 0; virtual bool IsStarted() = 0;
// Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered // Returns a Handle to the renderer image ressource or nullptr if it failed to create the resource, the handle can be used in ImGui's Image calls, image_buffer must be RGBA ordered

View File

@ -84,7 +84,7 @@ void OpenGLX_Hook::_PrepareForOverlay(Display* display, GLXDrawable drawable)
{ {
if( !_Initialized ) if( !_Initialized )
{ {
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
//int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid. //int attributes[] = { //can't be const b/c X11 doesn't like it. Not sure if that's intentional or just stupid.

View File

@ -128,8 +128,7 @@ Steam_Overlay::Steam_Overlay(Settings* settings, SteamCallResults* callback_resu
i_have_lobby(false), i_have_lobby(false),
show_achievements(false), show_achievements(false),
show_settings(false), show_settings(false),
_renderer(nullptr), _renderer(nullptr)
fonts_atlas(nullptr)
{ {
strncpy(username_text, settings->get_local_name(), sizeof(username_text)); strncpy(username_text, settings->get_local_name(), sizeof(username_text));
@ -208,7 +207,7 @@ void Steam_Overlay::UnSetupOverlay()
if (!Ready() && future_renderer.valid()) { if (!Ready() && future_renderer.valid()) {
if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) { if (future_renderer.wait_for(std::chrono::milliseconds{500}) == std::future_status::ready) {
future_renderer.get(); future_renderer.get();
ingame_overlay::FreeDetector(); ingame_overlay::FreeRendererDetection();
} }
} }
} }
@ -710,10 +709,11 @@ void Steam_Overlay::BuildNotifications(int width, int height)
void Steam_Overlay::CreateFonts() void Steam_Overlay::CreateFonts()
{ {
if (fonts_atlas) return; //TODO: remove from dx_whatever hook
if(ImGui::GetCurrentContext() == nullptr)
ImFontAtlas *Fonts = new ImFontAtlas(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
ImFontConfig fontcfg; ImFontConfig fontcfg;
float font_size = 16.0; float font_size = 16.0;
@ -727,7 +727,7 @@ void Steam_Overlay::CreateFonts()
font_builder.AddText(x.description.c_str()); font_builder.AddText(x.description.c_str());
} }
font_builder.AddRanges(Fonts->GetGlyphRangesDefault()); font_builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
ImVector<ImWchar> ranges; ImVector<ImWchar> ranges;
font_builder.BuildRanges(&ranges); font_builder.BuildRanges(&ranges);
@ -744,11 +744,11 @@ void Steam_Overlay::CreateFonts()
ImFont *font = NULL; ImFont *font = NULL;
#if defined(__WINDOWS__) #if defined(__WINDOWS__)
font = Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\micross.ttf", font_size, &fontcfg); font = io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\micross.ttf", font_size, &fontcfg);
#endif #endif
if (!font) { if (!font) {
font = Fonts->AddFontDefault(&fontcfg); font = io.Fonts->AddFontDefault(&fontcfg);
} }
font_notif = font_default = font; font_notif = font_default = font;
@ -757,16 +757,15 @@ void Steam_Overlay::CreateFonts()
PRINT_DEBUG("loading extra fonts\n"); PRINT_DEBUG("loading extra fonts\n");
fontcfg.MergeMode = true; fontcfg.MergeMode = true;
#if defined(__WINDOWS__) #if defined(__WINDOWS__)
Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\simsun.ttc", font_size, &fontcfg); io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\simsun.ttc", font_size, &fontcfg);
Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\malgun.ttf", font_size, &fontcfg); io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\malgun.ttf", font_size, &fontcfg);
#endif #endif
} }
Fonts->Build(); io.Fonts->Build();
fonts_atlas = (void *)Fonts;
// ImGuiStyle& style = ImGui::GetStyle(); ImGuiStyle& style = ImGui::GetStyle();
// style.WindowRounding = 0.0; // Disable round window style.WindowRounding = 0.0; // Disable round window
reset_LastError(); reset_LastError();
} }
@ -1049,7 +1048,6 @@ void Steam_Overlay::RunCallbacks()
auto callback = std::bind(&Steam_Overlay::OpenOverlayHook, this, std::placeholders::_1); auto callback = std::bind(&Steam_Overlay::OpenOverlayHook, this, std::placeholders::_1);
PRINT_DEBUG("start renderer\n", _renderer); PRINT_DEBUG("start renderer\n", _renderer);
std::set<ingame_overlay::ToggleKey> keys = {ingame_overlay::ToggleKey::SHIFT, ingame_overlay::ToggleKey::TAB}; std::set<ingame_overlay::ToggleKey> keys = {ingame_overlay::ToggleKey::SHIFT, ingame_overlay::ToggleKey::TAB};
_renderer->ImGuiFontAtlas = fonts_atlas;
bool started = _renderer->StartHook(callback, keys); bool started = _renderer->StartHook(callback, keys);
PRINT_DEBUG("tried to start renderer %u\n", started); PRINT_DEBUG("tried to start renderer %u\n", started);
} }

View File

@ -102,7 +102,6 @@ class Steam_Overlay
std::string show_url; std::string show_url;
std::vector<Overlay_Achievement> achievements; std::vector<Overlay_Achievement> achievements;
bool show_achievements, show_settings; bool show_achievements, show_settings;
void *fonts_atlas;
bool disable_forced, local_save, warning_forced; bool disable_forced, local_save, warning_forced;
uint32_t appid; uint32_t appid;

View File

@ -115,7 +115,7 @@ void DX10_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView); pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
pBackBuffer->Release(); pBackBuffer->Release();
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplDX10_Init(pDevice); ImGui_ImplDX10_Init(pDevice);
Windows_Hook::Inst()->SetInitialWindowSize(desc.OutputWindow); Windows_Hook::Inst()->SetInitialWindowSize(desc.OutputWindow);

View File

@ -147,7 +147,7 @@ void DX11_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain)
return; return;
if(ImGui::GetCurrentContext() == nullptr) if(ImGui::GetCurrentContext() == nullptr)
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplDX11_Init(pDevice, pContext); ImGui_ImplDX11_Init(pDevice, pContext);

View File

@ -264,7 +264,7 @@ void DX12_Hook::_PrepareForOverlay(IDXGISwapChain* pSwapChain, ID3D12CommandQueu
//auto heaps = std::move(get_free_texture_heap()); //auto heaps = std::move(get_free_texture_heap());
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, pSrvDescHeap, ImGui_ImplDX12_Init(pDevice, bufferCount, DXGI_FORMAT_R8G8B8A8_UNORM, pSrvDescHeap,
pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(), pSrvDescHeap->GetCPUDescriptorHandleForHeapStart(),
pSrvDescHeap->GetGPUDescriptorHandleForHeapStart()); pSrvDescHeap->GetGPUDescriptorHandleForHeapStart());

View File

@ -133,7 +133,7 @@ void DX9_Hook::_PrepareForOverlay(IDirect3DDevice9 *pDevice, HWND destWindow)
pDevice->AddRef(); pDevice->AddRef();
_pDevice = pDevice; _pDevice = pDevice;
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplDX9_Init(pDevice); ImGui_ImplDX9_Init(pDevice);
_LastWindow = destWindow; _LastWindow = destWindow;

View File

@ -86,7 +86,7 @@ void OpenGL_Hook::_PrepareForOverlay(HDC hDC)
if (!_Initialized) if (!_Initialized)
{ {
ImGui::CreateContext((ImFontAtlas *)ImGuiFontAtlas); ImGui::CreateContext();
ImGui_ImplOpenGL3_Init(); ImGui_ImplOpenGL3_Init();
_LastWindow = hWnd; _LastWindow = hWnd;