2020-04-01 08:20:55 +00:00
|
|
|
#include <X11/Xlib.h>
|
2020-03-10 05:19:18 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <array>
|
2020-04-21 17:57:13 +00:00
|
|
|
#include <thread>
|
|
|
|
#include <vector>
|
|
|
|
#include <algorithm>
|
2020-08-18 16:13:27 +00:00
|
|
|
#include <atomic>
|
2020-03-10 05:19:18 +00:00
|
|
|
#include <cstring>
|
2021-07-16 00:28:46 +00:00
|
|
|
#include <spdlog/spdlog.h>
|
2020-03-10 05:19:18 +00:00
|
|
|
#include "real_dlsym.h"
|
2020-04-01 12:02:56 +00:00
|
|
|
#include "loaders/loader_glx.h"
|
2020-04-01 22:30:47 +00:00
|
|
|
#include "loaders/loader_x11.h"
|
2020-03-10 05:19:18 +00:00
|
|
|
#include "mesa/util/macros.h"
|
|
|
|
#include "mesa/util/os_time.h"
|
2020-04-18 16:05:17 +00:00
|
|
|
#include "blacklist.h"
|
2020-03-10 05:19:18 +00:00
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
#include <iomanip>
|
|
|
|
|
2021-03-30 01:56:38 +00:00
|
|
|
#include <glad/glad.h>
|
2022-05-16 08:30:58 +00:00
|
|
|
#include "gl_hud.h"
|
2020-04-01 22:30:47 +00:00
|
|
|
|
|
|
|
using namespace MangoHud::GL;
|
|
|
|
|
2020-04-10 19:36:35 +00:00
|
|
|
#ifndef GLX_WIDTH
|
|
|
|
#define GLX_WIDTH 0x801D
|
2021-03-30 01:56:38 +00:00
|
|
|
#define GLX_HEIGHT 0x801E
|
2020-04-10 19:36:35 +00:00
|
|
|
#endif
|
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
static glx_loader glx;
|
2020-03-10 05:19:18 +00:00
|
|
|
|
2020-08-18 16:13:27 +00:00
|
|
|
static std::atomic<int> refcnt (0);
|
2020-04-21 17:57:13 +00:00
|
|
|
|
2023-03-03 10:43:59 +00:00
|
|
|
static void* get_glx_proc_address(const char* name) {
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2020-03-10 05:19:18 +00:00
|
|
|
|
2020-03-13 07:35:14 +00:00
|
|
|
void *func = nullptr;
|
2020-04-01 12:20:22 +00:00
|
|
|
if (glx.GetProcAddress)
|
|
|
|
func = glx.GetProcAddress( (const unsigned char*) name );
|
2020-03-10 05:19:18 +00:00
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
if (!func && glx.GetProcAddressARB)
|
|
|
|
func = glx.GetProcAddressARB( (const unsigned char*) name );
|
2020-03-10 05:19:18 +00:00
|
|
|
|
|
|
|
if (!func)
|
|
|
|
func = get_proc_address( name );
|
|
|
|
|
2020-04-09 18:26:00 +00:00
|
|
|
if (!func) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_ERROR("Failed to get function '{}'", name);
|
2020-04-09 18:26:00 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
return func;
|
|
|
|
}
|
|
|
|
|
2022-07-09 12:44:57 +00:00
|
|
|
bool glx_mesa_queryInteger(int attrib, unsigned int *value);
|
|
|
|
bool glx_mesa_queryInteger(int attrib, unsigned int *value)
|
|
|
|
{
|
|
|
|
static int (*pfn_queryInteger)(int attribute, unsigned int *value) =
|
|
|
|
reinterpret_cast<decltype(pfn_queryInteger)>(get_glx_proc_address(
|
|
|
|
"glXQueryCurrentRendererIntegerMESA"));
|
|
|
|
if (pfn_queryInteger)
|
|
|
|
return !!pfn_queryInteger(attrib, value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
EXPORT_C_(void *) glXCreateContext(void *dpy, void *vis, void *shareList, int direct)
|
|
|
|
{
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
|
|
|
void *ctx = glx.CreateContext(dpy, vis, shareList, direct);
|
2020-08-18 16:13:27 +00:00
|
|
|
if (ctx)
|
|
|
|
refcnt++;
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, ctx);
|
2020-03-10 05:19:18 +00:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
2023-03-03 10:43:59 +00:00
|
|
|
EXPORT_C_(void *) glXCreateContextAttribs(void *dpy, void *config,void *share_context, int direct, const int *attrib_list);
|
2020-08-18 16:13:27 +00:00
|
|
|
EXPORT_C_(void *) glXCreateContextAttribs(void *dpy, void *config,void *share_context, int direct, const int *attrib_list)
|
|
|
|
{
|
|
|
|
glx.Load();
|
|
|
|
void *ctx = glx.CreateContextAttribs(dpy, config, share_context, direct, attrib_list);
|
|
|
|
if (ctx)
|
|
|
|
refcnt++;
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, ctx);
|
2020-08-18 16:13:27 +00:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(void *) glXCreateContextAttribsARB(void *dpy, void *config,void *share_context, int direct, const int *attrib_list)
|
|
|
|
{
|
|
|
|
glx.Load();
|
|
|
|
void *ctx = glx.CreateContextAttribsARB(dpy, config, share_context, direct, attrib_list);
|
|
|
|
if (ctx)
|
|
|
|
refcnt++;
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, ctx);
|
2020-08-18 16:13:27 +00:00
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(void) glXDestroyContext(void *dpy, void *ctx)
|
|
|
|
{
|
|
|
|
glx.Load();
|
|
|
|
glx.DestroyContext(dpy, ctx);
|
|
|
|
refcnt--;
|
|
|
|
if (refcnt <= 0)
|
|
|
|
imgui_shutdown();
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, ctx);
|
2020-08-18 16:13:27 +00:00
|
|
|
}
|
|
|
|
|
2020-04-10 19:29:49 +00:00
|
|
|
EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}, {}", __func__, drawable, ctx);
|
2020-04-10 19:29:49 +00:00
|
|
|
int ret = glx.MakeCurrent(dpy, drawable, ctx);
|
2020-04-18 16:05:17 +00:00
|
|
|
|
|
|
|
if (!is_blacklisted()) {
|
2020-04-21 17:57:13 +00:00
|
|
|
if (ret) {
|
2022-07-09 12:44:57 +00:00
|
|
|
imgui_set_context(ctx, gl_wsi::GL_WSI_GLX);
|
2023-10-10 01:22:37 +00:00
|
|
|
SPDLOG_DEBUG("GL ref count: {}", refcnt.load());
|
2020-04-21 17:57:13 +00:00
|
|
|
}
|
2020-04-18 16:05:17 +00:00
|
|
|
|
2021-02-03 16:50:31 +00:00
|
|
|
// Afaik -1 only works with EXT version if it has GLX_EXT_swap_control_tear, maybe EGL_MESA_swap_control_tear someday
|
2020-04-18 16:05:17 +00:00
|
|
|
if (params.gl_vsync >= -1) {
|
|
|
|
if (glx.SwapIntervalEXT)
|
|
|
|
glx.SwapIntervalEXT(dpy, drawable, params.gl_vsync);
|
2021-02-03 16:50:31 +00:00
|
|
|
}
|
|
|
|
if (params.gl_vsync >= 0) {
|
2020-04-18 16:05:17 +00:00
|
|
|
if (glx.SwapIntervalSGI)
|
|
|
|
glx.SwapIntervalSGI(params.gl_vsync);
|
|
|
|
if (glx.SwapIntervalMESA)
|
|
|
|
glx.SwapIntervalMESA(params.gl_vsync);
|
|
|
|
}
|
2020-03-13 08:05:41 +00:00
|
|
|
}
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-05-08 19:53:33 +00:00
|
|
|
static void do_imgui_swap(void *dpy, void *drawable)
|
|
|
|
{
|
2021-03-30 01:56:38 +00:00
|
|
|
GLint vp[4];
|
2020-04-18 16:05:17 +00:00
|
|
|
if (!is_blacklisted()) {
|
2022-07-09 12:44:57 +00:00
|
|
|
imgui_create(glx.GetCurrentContext(), gl_wsi::GL_WSI_GLX);
|
2020-04-18 16:05:17 +00:00
|
|
|
|
|
|
|
unsigned int width = -1, height = -1;
|
|
|
|
|
2021-03-30 01:56:38 +00:00
|
|
|
switch (params.gl_size_query)
|
|
|
|
{
|
|
|
|
case GL_SIZE_VIEWPORT:
|
|
|
|
glGetIntegerv (GL_VIEWPORT, vp);
|
|
|
|
width = vp[2];
|
|
|
|
height = vp[3];
|
|
|
|
break;
|
|
|
|
case GL_SIZE_SCISSORBOX:
|
|
|
|
glGetIntegerv (GL_SCISSOR_BOX, vp);
|
|
|
|
width = vp[2];
|
|
|
|
height = vp[3];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
glx.QueryDrawable(dpy, drawable, GLX_WIDTH, &width);
|
|
|
|
glx.QueryDrawable(dpy, drawable, GLX_HEIGHT, &height);
|
|
|
|
break;
|
|
|
|
}
|
2020-04-18 16:05:17 +00:00
|
|
|
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_TRACE("swap buffers: {}x{}", width, height);
|
2020-04-18 16:05:17 +00:00
|
|
|
imgui_render(width, height);
|
|
|
|
}
|
2020-05-08 19:53:33 +00:00
|
|
|
}
|
2020-04-01 08:25:55 +00:00
|
|
|
|
2020-05-08 19:53:33 +00:00
|
|
|
EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) {
|
|
|
|
glx.Load();
|
|
|
|
|
|
|
|
do_imgui_swap(dpy, drawable);
|
2020-06-24 18:14:24 +00:00
|
|
|
using namespace std::chrono_literals;
|
2023-03-16 01:59:38 +00:00
|
|
|
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s && fps_limit_stats.method == FPS_LIMIT_METHOD_EARLY){
|
2020-06-24 18:14:24 +00:00
|
|
|
fps_limit_stats.frameStart = Clock::now();
|
2020-03-10 05:19:18 +00:00
|
|
|
FpsLimiter(fps_limit_stats);
|
2020-06-24 18:14:24 +00:00
|
|
|
fps_limit_stats.frameEnd = Clock::now();
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|
2023-01-18 00:46:02 +00:00
|
|
|
glx.SwapBuffers(dpy, drawable);
|
2023-03-16 01:59:38 +00:00
|
|
|
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s && fps_limit_stats.method == FPS_LIMIT_METHOD_LATE){
|
|
|
|
fps_limit_stats.frameStart = Clock::now();
|
|
|
|
FpsLimiter(fps_limit_stats);
|
|
|
|
fps_limit_stats.frameEnd = Clock::now();
|
|
|
|
}
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|
|
|
|
|
2020-05-08 19:53:33 +00:00
|
|
|
EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder)
|
|
|
|
{
|
|
|
|
glx.Load();
|
2021-02-03 16:50:31 +00:00
|
|
|
if (!glx.SwapBuffersMscOML)
|
2021-02-03 17:01:31 +00:00
|
|
|
return -1;
|
2020-05-08 19:53:33 +00:00
|
|
|
|
|
|
|
do_imgui_swap(dpy, drawable);
|
2020-06-24 18:14:24 +00:00
|
|
|
using namespace std::chrono_literals;
|
2023-03-16 01:59:38 +00:00
|
|
|
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s && fps_limit_stats.method == FPS_LIMIT_METHOD_EARLY){
|
2020-06-24 18:14:24 +00:00
|
|
|
fps_limit_stats.frameStart = Clock::now();
|
2020-05-08 19:53:33 +00:00
|
|
|
FpsLimiter(fps_limit_stats);
|
2020-06-24 18:14:24 +00:00
|
|
|
fps_limit_stats.frameEnd = Clock::now();
|
2020-05-08 19:53:33 +00:00
|
|
|
}
|
2023-03-16 01:59:38 +00:00
|
|
|
|
2023-01-18 00:46:02 +00:00
|
|
|
int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder);
|
|
|
|
|
2023-03-16 01:59:38 +00:00
|
|
|
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s && fps_limit_stats.method == FPS_LIMIT_METHOD_LATE){
|
|
|
|
fps_limit_stats.frameStart = Clock::now();
|
|
|
|
FpsLimiter(fps_limit_stats);
|
|
|
|
fps_limit_stats.frameEnd = Clock::now();
|
|
|
|
}
|
|
|
|
|
2020-05-08 19:53:33 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-03-12 10:11:31 +00:00
|
|
|
EXPORT_C_(void) glXSwapIntervalEXT(void *dpy, void *draw, int interval) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, interval);
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2021-02-03 16:50:31 +00:00
|
|
|
if (!glx.SwapIntervalEXT)
|
|
|
|
return;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
|
|
|
if (!is_blacklisted() && params.gl_vsync >= 0)
|
2020-03-12 10:11:31 +00:00
|
|
|
interval = params.gl_vsync;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.SwapIntervalEXT(dpy, draw, interval);
|
2020-03-12 10:11:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(int) glXSwapIntervalSGI(int interval) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, interval);
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2021-02-03 16:50:31 +00:00
|
|
|
if (!glx.SwapIntervalSGI)
|
|
|
|
return -1;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
|
|
|
if (!is_blacklisted() && params.gl_vsync >= 0)
|
2020-03-12 10:11:31 +00:00
|
|
|
interval = params.gl_vsync;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
return glx.SwapIntervalSGI(interval);
|
2020-03-12 10:11:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(int) glXSwapIntervalMESA(unsigned int interval) {
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, interval);
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2021-02-03 16:50:31 +00:00
|
|
|
if (!glx.SwapIntervalMESA)
|
|
|
|
return -1;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
|
|
|
if (!is_blacklisted() && params.gl_vsync >= 0)
|
2020-03-12 10:11:31 +00:00
|
|
|
interval = (unsigned int)params.gl_vsync;
|
2020-04-18 16:05:17 +00:00
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
return glx.SwapIntervalMESA(interval);
|
2020-03-12 10:11:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(int) glXGetSwapIntervalMESA() {
|
2020-04-01 12:20:22 +00:00
|
|
|
glx.Load();
|
2021-02-03 16:50:31 +00:00
|
|
|
if (!glx.GetSwapIntervalMESA)
|
|
|
|
return 0;
|
|
|
|
|
2020-04-01 12:20:22 +00:00
|
|
|
int interval = glx.GetSwapIntervalMESA();
|
2020-03-12 10:11:31 +00:00
|
|
|
|
2020-04-18 16:05:17 +00:00
|
|
|
if (!is_blacklisted()) {
|
|
|
|
static bool first_call = true;
|
|
|
|
|
|
|
|
if (first_call) {
|
|
|
|
first_call = false;
|
|
|
|
if (params.gl_vsync >= 0) {
|
|
|
|
interval = params.gl_vsync;
|
|
|
|
glx.SwapIntervalMESA(interval);
|
|
|
|
}
|
2020-03-12 10:11:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 16:48:45 +00:00
|
|
|
SPDLOG_DEBUG("{}: {}", __func__, interval);
|
2020-03-12 10:11:31 +00:00
|
|
|
return interval;
|
|
|
|
}
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
struct func_ptr {
|
|
|
|
const char *name;
|
|
|
|
void *ptr;
|
|
|
|
};
|
|
|
|
|
2020-08-18 16:13:27 +00:00
|
|
|
static std::array<const func_ptr, 13> name_to_funcptr_map = {{
|
2020-03-10 05:19:18 +00:00
|
|
|
#define ADD_HOOK(fn) { #fn, (void *) fn }
|
|
|
|
ADD_HOOK(glXGetProcAddress),
|
|
|
|
ADD_HOOK(glXGetProcAddressARB),
|
2020-08-18 16:13:27 +00:00
|
|
|
ADD_HOOK(glXCreateContextAttribs),
|
|
|
|
ADD_HOOK(glXCreateContextAttribsARB),
|
2020-03-10 05:19:18 +00:00
|
|
|
ADD_HOOK(glXCreateContext),
|
2020-08-18 16:13:27 +00:00
|
|
|
ADD_HOOK(glXDestroyContext),
|
2020-03-10 05:19:18 +00:00
|
|
|
ADD_HOOK(glXMakeCurrent),
|
|
|
|
ADD_HOOK(glXSwapBuffers),
|
2020-05-08 19:53:33 +00:00
|
|
|
ADD_HOOK(glXSwapBuffersMscOML),
|
2020-03-12 10:11:31 +00:00
|
|
|
|
|
|
|
ADD_HOOK(glXSwapIntervalEXT),
|
|
|
|
ADD_HOOK(glXSwapIntervalSGI),
|
|
|
|
ADD_HOOK(glXSwapIntervalMESA),
|
|
|
|
ADD_HOOK(glXGetSwapIntervalMESA),
|
2020-03-10 05:19:18 +00:00
|
|
|
#undef ADD_HOOK
|
|
|
|
}};
|
|
|
|
|
2023-03-03 10:43:59 +00:00
|
|
|
EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name);
|
2020-04-21 13:56:46 +00:00
|
|
|
EXPORT_C_(void *) mangohud_find_glx_ptr(const char *name)
|
2020-03-10 05:19:18 +00:00
|
|
|
{
|
2020-04-18 16:05:17 +00:00
|
|
|
if (is_blacklisted())
|
|
|
|
return nullptr;
|
|
|
|
|
2020-03-10 05:19:18 +00:00
|
|
|
for (auto& func : name_to_funcptr_map) {
|
|
|
|
if (strcmp(name, func.name) == 0)
|
|
|
|
return func.ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName) {
|
2021-02-03 16:50:31 +00:00
|
|
|
void *real_func = get_glx_proc_address((const char*)procName);
|
|
|
|
void *func = mangohud_find_glx_ptr( (const char*)procName );
|
2023-10-10 02:21:57 +00:00
|
|
|
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func);
|
2021-07-16 00:28:46 +00:00
|
|
|
|
2021-02-03 16:50:31 +00:00
|
|
|
if (func && real_func)
|
2020-03-10 05:19:18 +00:00
|
|
|
return func;
|
|
|
|
|
2021-02-03 16:50:31 +00:00
|
|
|
return real_func;
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName) {
|
2021-02-03 16:50:31 +00:00
|
|
|
void *real_func = get_glx_proc_address((const char*)procName);
|
|
|
|
void *func = mangohud_find_glx_ptr( (const char*)procName );
|
2023-10-10 02:21:57 +00:00
|
|
|
SPDLOG_TRACE("{}: '{}', real: {}, fun: {}", __func__, reinterpret_cast<const char*>(procName), real_func, func);
|
2023-10-10 02:27:46 +00:00
|
|
|
if (func && real_func)
|
2020-03-10 05:19:18 +00:00
|
|
|
return func;
|
|
|
|
|
2021-02-03 16:50:31 +00:00
|
|
|
return real_func;
|
2020-03-10 05:19:18 +00:00
|
|
|
}
|