mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator
synced 2025-05-23 21:57:40 +08:00
Fix renderer detection under Wine.
Use new timing checks to detect D3D being dependant on other APIs. (Should work now regardless of platform, but GPU hardware detection may still be needed...)
This commit is contained in:
parent
32689355d0
commit
38cbfb3be9
@ -48,6 +48,12 @@
|
||||
#undef GetModuleHandle
|
||||
#endif
|
||||
|
||||
// Minimal timeout for detecting the real rendering API when multiple are used.
|
||||
#define MIN_RENDER_DETECT_TIMEOUT 1
|
||||
// Variance is in milliseconds. 1000 (one second) / 24 (FPS) = Aprox. 41.66 Milliseconds between frames.)
|
||||
#define MAX_RENDER_DETECT_FRAME_TIMING_VARIANCE 42
|
||||
#define GET_RENDERER_DETECT_TIMEOUT ((MAX_RENDERER_API_DETECT_TIMEOUT > MIN_RENDER_DETECT_TIMEOUT) ? MAX_RENDERER_API_DETECT_TIMEOUT : MIN_RENDER_DETECT_TIMEOUT) * 1000
|
||||
|
||||
#elif defined(__linux__) || defined(linux)
|
||||
#define RENDERERDETECTOR_OS_LINUX
|
||||
|
||||
@ -105,6 +111,15 @@ private:
|
||||
decltype(::SwapBuffers)* wglSwapBuffers;
|
||||
decltype(::vkQueuePresentKHR)* vkQueuePresentKHR;
|
||||
|
||||
std::mutex timing_detect_mutex;
|
||||
std::chrono::time_point<std::chrono::steady_clock> initial_hook_detect_time;
|
||||
std::chrono::time_point<std::chrono::steady_clock> d3d_hook_detect_time;
|
||||
std::chrono::time_point<std::chrono::steady_clock> ogl_hook_detect_time;
|
||||
std::chrono::time_point<std::chrono::steady_clock> vkn_hook_detect_time;
|
||||
std::chrono::steady_clock::duration d3d_frame_duration;
|
||||
std::chrono::steady_clock::duration ogl_frame_duration;
|
||||
std::chrono::steady_clock::duration vkn_frame_duration;
|
||||
|
||||
bool dxgi_hooked;
|
||||
bool dxgi1_2_hooked;
|
||||
bool dx12_hooked;
|
||||
@ -113,6 +128,7 @@ private:
|
||||
bool dx9_hooked;
|
||||
bool opengl_hooked;
|
||||
bool vulkan_hooked;
|
||||
bool wine_found;
|
||||
|
||||
DX12_Hook* dx12_hook;
|
||||
DX11_Hook* dx11_hook;
|
||||
@ -135,6 +151,7 @@ private:
|
||||
dx9_hooked(false),
|
||||
opengl_hooked(false),
|
||||
vulkan_hooked(false),
|
||||
wine_found(false),
|
||||
renderer_hook(nullptr),
|
||||
dx9_hook(nullptr),
|
||||
dx10_hook(nullptr),
|
||||
@ -257,6 +274,8 @@ private:
|
||||
|
||||
void DeduceDXVersionFromSwapChain(IDXGISwapChain* pSwapChain)
|
||||
{
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector DeduceDXVersionFromSwapChain");
|
||||
IUnknown* pDevice = nullptr;
|
||||
if (Inst()->dx12_hooked)
|
||||
{
|
||||
@ -294,21 +313,154 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckD3DHookDetectTimings()
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool ret = false;
|
||||
|
||||
// It appears that (NVidia at least) calls IDXGISwapChain when calling OpenGL or Vulkan SwapBuffers.
|
||||
//
|
||||
// ---BUT---
|
||||
//
|
||||
// Wine and it's derivatives will -always- pass the OpenGL or Vulkan renderer
|
||||
// detection, depending on what backend they are set to use for D3D.
|
||||
// (wined3d == OpenGL. vkd3d || vkd3d-proton || DXVK || etc. == Vulkan.)
|
||||
//
|
||||
// So pass this check if, under Windows, D3D's frame interval timing isn't close to
|
||||
// OpenGL's or Vulkan's. (I.e. Multiple frames have passed and only D3D has kept pace.)
|
||||
// --OR--
|
||||
// Invert the result under Windows to cover the NVIDIA case.
|
||||
// --OR--
|
||||
// Fail this check under Wine if OpenGL's / Vulkan's timing is the only regularly
|
||||
// incrementing value. (I.e. Multiple frames have passed and only OpenGL OR Vulkan is
|
||||
// keeping pace.)
|
||||
// --OR--
|
||||
// Pass this check under Wine if D3D's frame interval timing is keeping up with
|
||||
// OpenGL's / Vulkan's. (I.e. Multiple frames have passed, D3D and either OpenGL or
|
||||
// Vulkan has kept pace.)
|
||||
{
|
||||
if (inst->d3d_hook_detect_time != std::chrono::steady_clock::time_point() &&
|
||||
inst->d3d_frame_duration != std::chrono::steady_clock::duration())
|
||||
{
|
||||
if (inst->ogl_hook_detect_time != std::chrono::steady_clock::time_point() &&
|
||||
inst->ogl_frame_duration != std::chrono::steady_clock::duration())
|
||||
{
|
||||
std::chrono::duration<int, std::milli> duration_diff(0);
|
||||
if (inst->ogl_frame_duration > inst->d3d_frame_duration)
|
||||
{
|
||||
duration_diff = std::chrono::duration_cast<std::chrono::milliseconds>(inst->ogl_frame_duration - inst->d3d_frame_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
duration_diff = std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration - inst->ogl_frame_duration);
|
||||
}
|
||||
|
||||
if (duration_diff < std::chrono::duration<int, std::milli>(MAX_RENDER_DETECT_FRAME_TIMING_VARIANCE))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (!inst->wine_found)
|
||||
ret = !ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inst->vkn_hook_detect_time != std::chrono::steady_clock::time_point() &&
|
||||
inst->vkn_frame_duration != std::chrono::steady_clock::duration())
|
||||
{
|
||||
std::chrono::duration<int, std::milli> duration_diff(0);
|
||||
if (inst->vkn_frame_duration > inst->d3d_frame_duration)
|
||||
{
|
||||
duration_diff = std::chrono::duration_cast<std::chrono::milliseconds>(inst->vkn_frame_duration - inst->d3d_frame_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
duration_diff = std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration - inst->vkn_frame_duration);
|
||||
}
|
||||
|
||||
if (duration_diff < std::chrono::duration<int, std::milli>(MAX_RENDER_DETECT_FRAME_TIMING_VARIANCE))
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (!inst->wine_found)
|
||||
ret = !ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("%s %s.\n",
|
||||
"Renderer_Detector CheckD3DHookDetectTimings Correct API:",
|
||||
((ret == true) ? "D3D" : "OpenGL / Vulkan"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE MyIDXGISwapChain_Present(IDXGISwapChain* _this, UINT SyncInterval, UINT Flags)
|
||||
{
|
||||
auto inst = Inst();
|
||||
HRESULT res;
|
||||
bool locked;
|
||||
std::unique_lock<std::mutex> lk(inst->renderer_mutex, std::defer_lock);
|
||||
bool detect_pass = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present Initial time");
|
||||
}
|
||||
if (inst->d3d_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->d3d_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->d3d_hook_detect_time);
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = CheckD3DHookDetectTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It appears that (NVidia at least) calls IDXGISwapChain when calling OpenGL or Vulkan SwapBuffers.
|
||||
// So only lock when OpenGL or Vulkan hasn't already locked the mutex.
|
||||
locked = lk.try_lock();
|
||||
|
||||
res = (_this->*inst->IDXGISwapChainPresent)(SyncInterval, Flags);
|
||||
if (!locked || inst->detection_done)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->DeduceDXVersionFromSwapChain(_this);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -318,16 +470,60 @@ private:
|
||||
auto inst = Inst();
|
||||
HRESULT res;
|
||||
bool locked;
|
||||
std::unique_lock<std::mutex> lk(inst->renderer_mutex, std::defer_lock);
|
||||
bool detect_pass = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present1");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present1 Initial time");
|
||||
}
|
||||
if (inst->d3d_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present1 Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->d3d_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->d3d_hook_detect_time);
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyIDXGISwapChain_Present1 current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = CheckD3DHookDetectTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// It appears that (NVidia at least) calls IDXGISwapChain when calling OpenGL or Vulkan SwapBuffers.
|
||||
// So only lock when OpenGL or Vulkan hasn't already locked the mutex.
|
||||
locked = lk.try_lock();
|
||||
|
||||
res = (_this->*inst->IDXGISwapChainPresent1)(SyncInterval, Flags, pPresentParameters);
|
||||
if (!locked || inst->detection_done)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->DeduceDXVersionFromSwapChain(_this);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -335,13 +531,58 @@ private:
|
||||
static HRESULT STDMETHODCALLTYPE MyDX9Present(IDirect3DDevice9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion)
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool detect_pass = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9Present");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9Present Initial time");
|
||||
}
|
||||
if (inst->d3d_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9Present Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->d3d_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->d3d_hook_detect_time);
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyDX9Present current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = CheckD3DHookDetectTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto res = (_this->*inst->IDirect3DDevice9Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->HookDetected(inst->dx9_hook);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -349,13 +590,58 @@ private:
|
||||
static HRESULT STDMETHODCALLTYPE MyDX9PresentEx(IDirect3DDevice9Ex* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool detect_pass = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9PresentEx");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9PresentEx Initial time");
|
||||
}
|
||||
if (inst->d3d_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9PresentEx Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->d3d_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->d3d_hook_detect_time);
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyDX9PresentEx current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = CheckD3DHookDetectTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto res = (_this->*inst->IDirect3DDevice9ExPresentEx)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->HookDetected(inst->dx9_hook);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -363,13 +649,58 @@ private:
|
||||
static HRESULT STDMETHODCALLTYPE MyDX9SwapChainPresent(IDirect3DSwapChain9* _this, CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion, DWORD dwFlags)
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool detect_pass = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9SwapChainPresent");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9SwapChainPresent Initial time");
|
||||
}
|
||||
if (inst->d3d_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyDX9SwapChainPresent Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->d3d_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->d3d_hook_detect_time);
|
||||
inst->d3d_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyDX9SwapChainPresent current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->d3d_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = CheckD3DHookDetectTimings();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto res = (_this->*inst->IDirect3DSwapChain9Present)(pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->HookDetected(inst->dx9_hook);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -377,14 +708,56 @@ private:
|
||||
static BOOL WINAPI MywglSwapBuffers(HDC hDC)
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool detect_pass = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MywglSwapBuffers");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MywglSwapBuffers Initial time");
|
||||
}
|
||||
if (inst->ogl_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->ogl_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MywglSwapBuffers Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->ogl_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->ogl_hook_detect_time);
|
||||
inst->ogl_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MywglSwapBuffers current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->ogl_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = !(CheckD3DHookDetectTimings());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto res = inst->wglSwapBuffers(hDC);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (gladLoaderLoadGL() >= GLAD_MAKE_VERSION(3, 1))
|
||||
{
|
||||
if (detect_pass == true && gladLoaderLoadGL() >= GLAD_MAKE_VERSION(3, 1))
|
||||
inst->HookDetected(inst->opengl_hook);
|
||||
}
|
||||
|
||||
@ -394,13 +767,58 @@ private:
|
||||
static VkResult VKAPI_CALL MyvkQueuePresentKHR(VkQueue Queue, const VkPresentInfoKHR* pPresentInfo)
|
||||
{
|
||||
auto inst = Inst();
|
||||
bool detect_pass = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyvkQueuePresentKHR");
|
||||
|
||||
if (!inst->detection_done)
|
||||
{
|
||||
auto current = std::chrono::steady_clock::now();
|
||||
std::lock_guard<std::mutex> t_lk(inst->timing_detect_mutex);
|
||||
if (inst->initial_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->initial_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyvkQueuePresentKHR Initial time");
|
||||
}
|
||||
if (inst->vkn_hook_detect_time == std::chrono::steady_clock::time_point())
|
||||
{
|
||||
inst->vkn_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector MyvkQueuePresentKHR Initial detect");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time) < std::chrono::milliseconds{GET_RENDERER_DETECT_TIMEOUT})
|
||||
{
|
||||
inst->vkn_frame_duration = std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->vkn_hook_detect_time);
|
||||
inst->vkn_hook_detect_time = current;
|
||||
PRINT_DEBUG("%s %" PRIu64 " %s %" PRIu64 "ms.\n",
|
||||
"Renderer_Detector MyvkQueuePresentKHR current frame duration:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(inst->vkn_frame_duration)).count(),
|
||||
"ms. time since first detect:",
|
||||
(std::chrono::duration_cast<std::chrono::milliseconds>(current - inst->initial_hook_detect_time)).count());
|
||||
}
|
||||
else
|
||||
{
|
||||
detect_pass = !(CheckD3DHookDetectTimings());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto res = inst->vkQueuePresentKHR(Queue, pPresentInfo);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(inst->renderer_mutex);
|
||||
if (inst->detection_done)
|
||||
return res;
|
||||
|
||||
if (detect_pass)
|
||||
inst->HookDetected(inst->vulkan_hook);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -644,6 +1062,24 @@ private:
|
||||
|
||||
pDXGIFactory->CreateSwapChainForHwnd(pDevice, dummyWindow, &SwapChainDesc, NULL, NULL, reinterpret_cast<IDXGISwapChain1**>(&pSwapChain));
|
||||
}
|
||||
else
|
||||
{
|
||||
SPDLOG_WARN("Failed to instanciate IDXGIFactory2, fallback to pure DX10 detection");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SPDLOG_WARN("Failed to instanciate ID3D10Device, fallback to pure DX10 detection");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (D3D10CreateDevice == nullptr)
|
||||
{
|
||||
SPDLOG_WARN("Failed to get address of D3D10CreateDevice, fallback to pure DX10 detection");
|
||||
} else
|
||||
{
|
||||
SPDLOG_WARN("Failed to get address of CreateDXGIFactory1, fallback to pure DX10 detection");
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,6 +1115,10 @@ private:
|
||||
|
||||
D3D10CreateDeviceAndSwapChain(NULL, (found_wine) ? D3D10_DRIVER_TYPE_WARP : D3D10_DRIVER_TYPE_NULL, NULL, 0, D3D10_SDK_VERSION, &SwapChainDesc, &pSwapChain, &pDevice);
|
||||
}
|
||||
else
|
||||
{
|
||||
SPDLOG_WARN("Failed to get address of D3D10CreateDeviceAndSwapChain, DX10 API failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (pSwapChain != nullptr)
|
||||
@ -775,7 +1215,17 @@ private:
|
||||
SwapChainDesc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
|
||||
pDXGIFactory->CreateSwapChainForHwnd(pDevice, dummyWindow, &SwapChainDesc, NULL, NULL, reinterpret_cast<IDXGISwapChain1**>(&pSwapChain));
|
||||
} else {
|
||||
SPDLOG_WARN("Failed to instanciate IDXGIFactory2, fallback to pure DX11 detection");
|
||||
}
|
||||
} else {
|
||||
SPDLOG_WARN("Failed to instanciate ID3D11Device, fallback to pure DX11 detection");
|
||||
}
|
||||
} else {
|
||||
if (D3D11CreateDevice == nullptr) {
|
||||
SPDLOG_WARN("Failed to get address of D3D11CreateDevice, fallback to pure DX11 detection");
|
||||
} else {
|
||||
SPDLOG_WARN("Failed to get address of CreateDXGIFactory1, fallback to pure DX11 detection");
|
||||
}
|
||||
}
|
||||
|
||||
@ -810,6 +1260,8 @@ private:
|
||||
SwapChainDesc.Windowed = TRUE;
|
||||
|
||||
D3D11CreateDeviceAndSwapChain(NULL, (found_wine) ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_NULL, NULL, 0, NULL, NULL, D3D11_SDK_VERSION, &SwapChainDesc, &pSwapChain, &pDevice, NULL, NULL);
|
||||
} else {
|
||||
SPDLOG_WARN("Failed to get address of D3D11CreateDeviceAndSwapChain, DX11 API failed.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1079,6 +1531,20 @@ private:
|
||||
|
||||
bool EnterDetection()
|
||||
{
|
||||
std::string ntdll_path = FindPreferedModulePath("ntdll.dll");
|
||||
if (!ntdll_path.empty())
|
||||
{
|
||||
HMODULE hNTdll = GetModuleHandleA(ntdll_path.c_str());
|
||||
if (hNTdll != nullptr)
|
||||
{
|
||||
auto wine_get_version = (const char*(*)())GetProcAddress(hNTdll, "wine_get_version");
|
||||
if (wine_get_version != nullptr)
|
||||
{
|
||||
wine_found = true;
|
||||
PRINT_DEBUG("Found WINE version: %s.\n", wine_get_version());
|
||||
}
|
||||
}
|
||||
}
|
||||
return CreateHWND() != nullptr;
|
||||
}
|
||||
|
||||
@ -1097,6 +1563,7 @@ private:
|
||||
dx9_hooked = false;
|
||||
opengl_hooked = false;
|
||||
vulkan_hooked = false;
|
||||
wine_found = false;
|
||||
|
||||
delete dx9_hook ; dx9_hook = nullptr;
|
||||
delete dx10_hook ; dx10_hook = nullptr;
|
||||
@ -1104,6 +1571,15 @@ private:
|
||||
delete dx12_hook ; dx12_hook = nullptr;
|
||||
delete opengl_hook; opengl_hook = nullptr;
|
||||
delete vulkan_hook; vulkan_hook = nullptr;
|
||||
|
||||
initial_hook_detect_time = std::chrono::time_point<std::chrono::steady_clock>();
|
||||
d3d_hook_detect_time = std::chrono::time_point<std::chrono::steady_clock>();
|
||||
ogl_hook_detect_time = std::chrono::time_point<std::chrono::steady_clock>();
|
||||
vkn_hook_detect_time = std::chrono::time_point<std::chrono::steady_clock>();
|
||||
|
||||
d3d_frame_duration = std::chrono::steady_clock::duration();
|
||||
ogl_frame_duration = std::chrono::steady_clock::duration();
|
||||
vkn_frame_duration = std::chrono::steady_clock::duration();
|
||||
}
|
||||
|
||||
#elif defined(RENDERERDETECTOR_OS_LINUX)
|
||||
@ -1346,6 +1822,22 @@ public:
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(stop_detection_mutex);
|
||||
|
||||
if (timeout != std::chrono::milliseconds{ -1 })
|
||||
{
|
||||
if (timeout < std::chrono::milliseconds{ GET_RENDERER_DETECT_TIMEOUT * 2 })
|
||||
{// Need enough time to determine API if multiple are used.
|
||||
timeout = std::chrono::milliseconds{ GET_RENDERER_DETECT_TIMEOUT * 2 };
|
||||
}
|
||||
PRINT_DEBUG("%s %" PRIu64 ".\n",
|
||||
"Renderer_Detector Detection timeout set to:",
|
||||
timeout.count());
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT_DEBUG("%s.\n",
|
||||
"Renderer_Detector Detection timeout set to: infinite");
|
||||
}
|
||||
|
||||
if (detection_count == 0)
|
||||
{// If we have no detections in progress, restart detection.
|
||||
detection_cancelled = false;
|
||||
|
@ -27,6 +27,21 @@
|
||||
|
||||
#include "Renderer_Hook.h"
|
||||
|
||||
/* Timeout is in seconds.
|
||||
Used for determining which rendering API is the real one used by
|
||||
the app when multiple APIs are used. (NVIDIA, Wine, etc.)
|
||||
|
||||
This is an internally used value, separate from the timeout given
|
||||
to DetectRenderer().
|
||||
|
||||
If you define it below the minimal level (one second), the minimal level
|
||||
will be used.
|
||||
|
||||
Any timeout given to DetectRenderer() less than this value will be upgraded
|
||||
to it.
|
||||
*/
|
||||
#define MAX_RENDERER_API_DETECT_TIMEOUT 1
|
||||
|
||||
namespace ingame_overlay {
|
||||
|
||||
std::future<Renderer_Hook*> DetectRenderer(std::chrono::milliseconds timeout = std::chrono::milliseconds{ -1 });
|
||||
|
@ -718,7 +718,7 @@ void Steam_Overlay::UnSetupOverlay()
|
||||
{
|
||||
ingame_overlay::StopRendererDetection();
|
||||
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::chrono::seconds{MAX_RENDERER_API_DETECT_TIMEOUT}) == std::future_status::ready) {
|
||||
future_renderer.get();
|
||||
ingame_overlay::FreeDetector();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user