WIP focus loss fps limiter

focus_loss
jackun 2 years ago
parent 05133ae3cd
commit 1df2d0f071
No known key found for this signature in database
GPG Key ID: 119DB3F1D05A9ED3

@ -85,11 +85,13 @@ vulkan_wsi_deps = []
if is_unixy if is_unixy
dep_x11 = dependency('x11', required: get_option('with_x11')) dep_x11 = dependency('x11', required: get_option('with_x11'))
dep_xcb = dependency('xcb', required: get_option('with_x11'))
dep_wayland_client = dependency('wayland-client', dep_wayland_client = dependency('wayland-client',
required: get_option('with_wayland'), version : '>=1.11') required: get_option('with_wayland'), version : '>=1.11')
dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true) dbus_dep = dependency('dbus-1', required: get_option('with_dbus')).partial_dependency(compile_args : true, includes : true)
else else
dep_x11 = null_dep dep_x11 = null_dep
dep_xcb = null_dep
dep_wayland_client = null_dep dep_wayland_client = null_dep
dbus_dep = null_dep dbus_dep = null_dep
endif endif
@ -98,6 +100,10 @@ if dep_x11.found()
vulkan_wsi_args += ['-DVK_USE_PLATFORM_XLIB_KHR'] vulkan_wsi_args += ['-DVK_USE_PLATFORM_XLIB_KHR']
vulkan_wsi_deps += dep_x11.partial_dependency(compile_args : true, includes : true) vulkan_wsi_deps += dep_x11.partial_dependency(compile_args : true, includes : true)
endif endif
if dep_xcb.found()
vulkan_wsi_args += ['-DVK_USE_PLATFORM_XCB_KHR']
vulkan_wsi_deps += dep_xcb #.partial_dependency(compile_args : true, includes : true)
endif
if dep_wayland_client.found() if dep_wayland_client.found()
vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR'] vulkan_wsi_args += ['-DVK_USE_PLATFORM_WAYLAND_KHR']
vulkan_wsi_deps += dep_wayland_client vulkan_wsi_deps += dep_wayland_client

@ -10,7 +10,7 @@ option('include_doc', type : 'boolean', value : true, description: 'Include the
option('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support') option('with_nvml', type : 'combo', value : 'enabled', choices: ['enabled', 'system', 'disabled'], description: 'Enable NVML support')
option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support') option('with_xnvctrl', type : 'feature', value : 'enabled', description: 'Enable XNVCtrl support')
option('with_x11', type : 'feature', value : 'enabled') option('with_x11', type : 'feature', value : 'enabled')
option('with_wayland', type : 'feature', value : 'disabled') option('with_wayland', type : 'feature', value : 'enabled')
option('with_dbus', type : 'feature', value : 'enabled') option('with_dbus', type : 'feature', value : 'enabled')
option('with_dlsym', type : 'feature', value : 'disabled') option('with_dlsym', type : 'feature', value : 'disabled')
option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build') option('loglevel', type: 'combo', choices : ['trace', 'debug', 'info', 'warn', 'err', 'critical', 'off'], value : 'info', description: 'Max log level in non-debug build')

@ -13,6 +13,7 @@
#include "file_utils.h" #include "file_utils.h"
#include "notify.h" #include "notify.h"
#include "blacklist.h" #include "blacklist.h"
#include "wsi_helpers.h"
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
#include "dbus_info.h" #include "dbus_info.h"
@ -53,6 +54,7 @@ struct state {
static GLVec last_vp {}, last_sb {}; static GLVec last_vp {}, last_sb {};
swapchain_stats sw_stats {}; swapchain_stats sw_stats {};
wsi_connection wsi_conn {};
static state state; static state state;
static uint32_t vendorID; static uint32_t vendorID;
static std::string deviceName; static std::string deviceName;
@ -75,6 +77,7 @@ void imgui_init()
init_spdlog(); init_spdlog();
parse_overlay_config(&params, getenv("MANGOHUD_CONFIG")); parse_overlay_config(&params, getenv("MANGOHUD_CONFIG"));
_params = &params; _params = &params;
sw_stats.wsi = &wsi_conn;
//check for blacklist item in the config file //check for blacklist item in the config file
for (auto& item : params.blacklist) { for (auto& item : params.blacklist) {

@ -13,6 +13,7 @@
#include "mesa/util/macros.h" #include "mesa/util/macros.h"
#include "mesa/util/os_time.h" #include "mesa/util/os_time.h"
#include "blacklist.h" #include "blacklist.h"
#include "wsi_helpers.h"
#include <chrono> #include <chrono>
#include <iomanip> #include <iomanip>
@ -22,6 +23,11 @@
using namespace MangoHud::GL; using namespace MangoHud::GL;
namespace MangoHud { namespace GL {
extern swapchain_stats sw_stats;
extern wsi_connection wsi_conn;
}}
EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName); EXPORT_C_(void *) glXGetProcAddress(const unsigned char* procName);
EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName); EXPORT_C_(void *) glXGetProcAddressARB(const unsigned char* procName);
@ -100,6 +106,7 @@ EXPORT_C_(int) glXMakeCurrent(void* dpy, void* drawable, void* ctx) {
int ret = glx.MakeCurrent(dpy, drawable, ctx); int ret = glx.MakeCurrent(dpy, drawable, ctx);
if (!is_blacklisted()) { if (!is_blacklisted()) {
if (ret) { if (ret) {
imgui_set_context(ctx); imgui_set_context(ctx);
SPDLOG_DEBUG("GL ref count: {}", refcnt); SPDLOG_DEBUG("GL ref count: {}", refcnt);
@ -127,6 +134,9 @@ static void do_imgui_swap(void *dpy, void *drawable)
if (!is_blacklisted()) { if (!is_blacklisted()) {
imgui_create(glx.GetCurrentContext()); imgui_create(glx.GetCurrentContext());
wsi_conn.xlib.dpy = (Display*)dpy;
wsi_conn.xlib.window = (Window)drawable;
unsigned int width = -1, height = -1; unsigned int width = -1, height = -1;
switch (params.gl_size_query) switch (params.gl_size_query)
@ -152,20 +162,27 @@ static void do_imgui_swap(void *dpy, void *drawable)
} }
} }
EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) { static void fps_limit()
glx.Load(); {
if (is_blacklisted())
do_imgui_swap(dpy, drawable); return;
glx.SwapBuffers(dpy, drawable);
using namespace std::chrono_literals; using namespace std::chrono_literals;
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s){ if (fps_limit_stats.targetFrameTime > 0s || (sw_stats.lost_focus && fps_limit_stats.focusLossFrameTime > 0s)){
fps_limit_stats.frameStart = Clock::now(); fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats); FpsLimiter(fps_limit_stats, sw_stats.lost_focus);
fps_limit_stats.frameEnd = Clock::now(); fps_limit_stats.frameEnd = Clock::now();
} }
} }
EXPORT_C_(void) glXSwapBuffers(void* dpy, void* drawable) {
glx.Load();
do_imgui_swap(dpy, drawable);
glx.SwapBuffers(dpy, drawable);
fps_limit();
}
EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder) EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t target_msc, int64_t divisor, int64_t remainder)
{ {
glx.Load(); glx.Load();
@ -174,13 +191,7 @@ EXPORT_C_(int64_t) glXSwapBuffersMscOML(void* dpy, void* drawable, int64_t targe
do_imgui_swap(dpy, drawable); do_imgui_swap(dpy, drawable);
int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder); int64_t ret = glx.SwapBuffersMscOML(dpy, drawable, target_msc, divisor, remainder);
fps_limit();
using namespace std::chrono_literals;
if (!is_blacklisted() && fps_limit_stats.targetFrameTime > 0s){
fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats);
fps_limit_stats.frameEnd = Clock::now();
}
return ret; return ret;
} }

@ -69,6 +69,30 @@ bool libx11_loader::Load(const std::string& library_name) {
return false; return false;
} }
XGetInputFocus =
reinterpret_cast<decltype(this->XGetInputFocus)>(
dlsym(library_, "XGetInputFocus"));
if (!XGetInputFocus) {
CleanUp(true);
return false;
}
XQueryTree =
reinterpret_cast<decltype(this->XQueryTree)>(
dlsym(library_, "XQueryTree"));
if (!XQueryTree) {
CleanUp(true);
return false;
}
XFree =
reinterpret_cast<decltype(this->XFree)>(
dlsym(library_, "XFree"));
if (!XFree) {
CleanUp(true);
return false;
}
loaded_ = true; loaded_ = true;
return true; return true;
} }

@ -20,7 +20,9 @@ class libx11_loader {
decltype(&::XKeysymToKeycode) XKeysymToKeycode; decltype(&::XKeysymToKeycode) XKeysymToKeycode;
decltype(&::XStringToKeysym) XStringToKeysym; decltype(&::XStringToKeysym) XStringToKeysym;
decltype(&::XGetGeometry) XGetGeometry; decltype(&::XGetGeometry) XGetGeometry;
decltype(&::XGetInputFocus) XGetInputFocus;
decltype(&::XQueryTree) XQueryTree;
decltype(&::XFree) XFree;
private: private:
void CleanUp(bool unload); void CleanUp(bool unload);

@ -41,6 +41,11 @@ foreach s : ['overlay.frag', 'overlay.vert']
command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@']) command : [glslang, '-V', '-x', '-o', '@OUTPUT@', '@INPUT@'])
endforeach endforeach
# files not to be included with mangoapp etc.
vklayer_files_only = files(
'wsi_helpers.cpp',
)
vklayer_files = files( vklayer_files = files(
'hud_elements.cpp', 'hud_elements.cpp',
'overlay.cpp', 'overlay.cpp',
@ -164,6 +169,7 @@ vklayer_mesa_overlay = shared_library(
util_files, util_files,
vk_enum_to_str, vk_enum_to_str,
vklayer_files, vklayer_files,
vklayer_files_only,
opengl_files, opengl_files,
overlay_spv, overlay_spv,
c_args : [ c_args : [
@ -216,8 +222,7 @@ if is_unixy
endif endif
if get_option('mangoapp') and sizeof_ptr == 8 if get_option('mangoapp') and sizeof_ptr == 8
pre_args += '-DIMGUI_IMPL_OPENGL_LOADER_GLEW' pre_args += ['-DIMGUI_IMPL_OPENGL_LOADER_GLEW', '-DMANGOAPP']
pre_args += '-DMANGOAPP'
mangoapp = executable( mangoapp = executable(
'mangoapp', 'mangoapp',
mangohud_version, mangohud_version,

@ -93,13 +93,17 @@ void init_spdlog()
} }
void FpsLimiter(struct fps_limit& stats){ void FpsLimiter(struct fps_limit& stats, bool lost_focus){
stats.sleepTime = stats.targetFrameTime - (stats.frameStart - stats.frameEnd); auto targetFrameTime = stats.targetFrameTime;
if (lost_focus && stats.focusLossFrameTime > 0s)
targetFrameTime = stats.focusLossFrameTime;
stats.sleepTime = targetFrameTime - (stats.frameStart - stats.frameEnd);
if (stats.sleepTime > stats.frameOverhead) { if (stats.sleepTime > stats.frameOverhead) {
auto adjustedSleep = stats.sleepTime - stats.frameOverhead; auto adjustedSleep = stats.sleepTime - stats.frameOverhead;
this_thread::sleep_for(adjustedSleep); this_thread::sleep_for(adjustedSleep);
stats.frameOverhead = ((Clock::now() - stats.frameStart) - adjustedSleep); stats.frameOverhead = ((Clock::now() - stats.frameStart) - adjustedSleep);
if (stats.frameOverhead > stats.targetFrameTime / 2) if (stats.frameOverhead > targetFrameTime / 2)
stats.frameOverhead = Clock::duration(0); stats.frameOverhead = Clock::duration(0);
} }
} }
@ -246,6 +250,11 @@ void update_hud_info_with_frametime(struct swapchain_stats& sw_stats, const stru
hw_update_thread = std::make_unique<hw_info_updater>(); hw_update_thread = std::make_unique<hw_info_updater>();
hw_update_thread->update(&params, vendorID); hw_update_thread->update(&params, vendorID);
#ifndef MANGOAPP
sw_stats.lost_focus = !window_has_focus(sw_stats.wsi);
SPDLOG_DEBUG("lost focus: {}", sw_stats.lost_focus);
#endif
sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed; sw_stats.fps = 1000000000.0 * sw_stats.n_frames_since_update / elapsed;
if (params.enabled[OVERLAY_PARAM_ENABLED_time]) { if (params.enabled[OVERLAY_PARAM_ENABLED_time]) {

@ -24,6 +24,7 @@ struct frame_stat {
static const int kMaxGraphEntries = 50; static const int kMaxGraphEntries = 50;
struct wsi_connection;
struct swapchain_stats { struct swapchain_stats {
uint64_t n_frames; uint64_t n_frames;
enum overlay_plots stat_selector; enum overlay_plots stat_selector;
@ -57,12 +58,16 @@ struct swapchain_stats {
std::string gpuName; std::string gpuName;
std::string driverName; std::string driverName;
enum EngineTypes engine; enum EngineTypes engine;
wsi_connection *wsi;
bool lost_focus;
}; };
struct fps_limit { struct fps_limit {
Clock::time_point frameStart; Clock::time_point frameStart;
Clock::time_point frameEnd; Clock::time_point frameEnd;
Clock::duration targetFrameTime; Clock::duration targetFrameTime;
Clock::duration focusLossFrameTime;
Clock::duration frameOverhead; Clock::duration frameOverhead;
Clock::duration sleepTime; Clock::duration sleepTime;
}; };
@ -105,7 +110,7 @@ void init_gpu_stats(uint32_t& vendorID, uint32_t reported_deviceID, overlay_para
void init_cpu_stats(overlay_params& params); void init_cpu_stats(overlay_params& params);
void check_keybinds(overlay_params& params, uint32_t vendorID); void check_keybinds(overlay_params& params, uint32_t vendorID);
void init_system_info(void); void init_system_info(void);
void FpsLimiter(struct fps_limit& stats); void FpsLimiter(struct fps_limit& stats, bool lost_focus = false);
std::string get_device_name(uint32_t vendorID, uint32_t deviceID); std::string get_device_name(uint32_t vendorID, uint32_t deviceID);
void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font); void create_fonts(const overlay_params& params, ImFont*& small_font, ImFont*& text_font);
void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...); void right_aligned_text(ImVec4& col, float off_x, const char *fmt, ...);
@ -119,5 +124,6 @@ extern void process_control_socket(int& control_client, overlay_params &params);
void render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing); void render_mpris_metadata(const overlay_params& params, mutexed_metadata& meta, uint64_t frame_timing);
#endif #endif
void update_fan(); void update_fan();
bool window_has_focus(const wsi_connection*);
#endif //MANGOHUD_OVERLAY_H #endif //MANGOHUD_OVERLAY_H

@ -410,6 +410,7 @@ parse_gl_size_query(const char *str)
#define parse_round_corners(s) parse_unsigned(s) #define parse_round_corners(s) parse_unsigned(s)
#define parse_fcat_overlay_width(s) parse_unsigned(s) #define parse_fcat_overlay_width(s) parse_unsigned(s)
#define parse_fcat_screen_edge(s) parse_unsigned(s) #define parse_fcat_screen_edge(s) parse_unsigned(s)
#define parse_focus_loss_fps_limit(s) parse_unsigned(s)
#define parse_cpu_color(s) parse_color(s) #define parse_cpu_color(s) parse_color(s)
#define parse_gpu_color(s) parse_color(s) #define parse_gpu_color(s) parse_color(s)
@ -792,6 +793,11 @@ parse_overlay_config(struct overlay_params *params,
else else
fps_limit_stats.targetFrameTime = {}; fps_limit_stats.targetFrameTime = {};
if (params->focus_loss_fps_limit > 0)
fps_limit_stats.focusLossFrameTime = duration_cast<Clock::duration>(duration<double>(1) / params->focus_loss_fps_limit);
else
fps_limit_stats.focusLossFrameTime = {};
#ifdef HAVE_DBUS #ifdef HAVE_DBUS
if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) { if (params->enabled[OVERLAY_PARAM_ENABLED_media_player]) {
if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_MPRIS)) if (dbusmgr::dbus_mgr.init(dbusmgr::SRV_MPRIS))

@ -101,6 +101,7 @@ typedef unsigned long KeySym;
OVERLAY_PARAM_CUSTOM(no_display) \ OVERLAY_PARAM_CUSTOM(no_display) \
OVERLAY_PARAM_CUSTOM(control) \ OVERLAY_PARAM_CUSTOM(control) \
OVERLAY_PARAM_CUSTOM(fps_limit) \ OVERLAY_PARAM_CUSTOM(fps_limit) \
OVERLAY_PARAM_CUSTOM(focus_loss_fps_limit) \
OVERLAY_PARAM_CUSTOM(vsync) \ OVERLAY_PARAM_CUSTOM(vsync) \
OVERLAY_PARAM_CUSTOM(gl_vsync) \ OVERLAY_PARAM_CUSTOM(gl_vsync) \
OVERLAY_PARAM_CUSTOM(gl_size_query) \ OVERLAY_PARAM_CUSTOM(gl_size_query) \
@ -204,6 +205,7 @@ struct overlay_params {
int control; int control;
uint32_t fps_sampling_period; /* ns */ uint32_t fps_sampling_period; /* ns */
std::vector<std::uint32_t> fps_limit; std::vector<std::uint32_t> fps_limit;
unsigned focus_loss_fps_limit;
bool help; bool help;
bool no_display; bool no_display;
bool full; bool full;

@ -49,6 +49,7 @@
#include "notify.h" #include "notify.h"
#include "blacklist.h" #include "blacklist.h"
#include "pci_ids.h" #include "pci_ids.h"
#include "wsi_helpers.h"
using namespace std; using namespace std;
@ -62,6 +63,12 @@ namespace MangoHud { namespace GL {
}} }}
#endif #endif
struct surface_data {
VkSurfaceKHR surface;
bool changed_flags;
wsi_connection wsi;
};
/* Mapped from VkInstace/VkPhysicalDevice */ /* Mapped from VkInstace/VkPhysicalDevice */
struct instance_data { struct instance_data {
struct vk_instance_dispatch_table vtable; struct vk_instance_dispatch_table vtable;
@ -132,6 +139,7 @@ struct overlay_draw {
/* Mapped from VkSwapchainKHR */ /* Mapped from VkSwapchainKHR */
struct swapchain_data { struct swapchain_data {
struct device_data *device; struct device_data *device;
struct surface_data *surface_data;
VkSwapchainKHR swapchain; VkSwapchainKHR swapchain;
unsigned width, height; unsigned width, height;
@ -398,6 +406,77 @@ static void destroy_swapchain_data(struct swapchain_data *data)
delete data; delete data;
} }
static struct surface_data *new_surface_data(VkSurfaceKHR surface)
{
struct surface_data *data = new surface_data();
data->surface = surface;
map_object(HKEY(data->surface), data);
return data;
}
static void destroy_surface_data(struct surface_data *data)
{
unmap_object(HKEY(data->surface));
delete data;
}
#ifdef VK_USE_PLATFORM_XCB_KHR
static VkResult overlay_CreateXcbSurfaceKHR(VkInstance instance, const VkXcbSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
{
SPDLOG_DEBUG("{}", __func__);
struct instance_data *instance_data = FIND(struct instance_data, instance);
VkResult result = instance_data->vtable.CreateXcbSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
if (result == VK_SUCCESS) {
struct surface_data *data = new_surface_data(*pSurface);
data->wsi.xcb.conn = pCreateInfo->connection;
data->wsi.xcb.window = pCreateInfo->window;
}
return result;
}
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
static VkResult overlay_CreateXlibSurfaceKHR(VkInstance instance, const VkXlibSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
{
SPDLOG_DEBUG("{}", __func__);
struct instance_data *instance_data = FIND(struct instance_data, instance);
VkResult result = instance_data->vtable.CreateXlibSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
if (result == VK_SUCCESS) {
struct surface_data *data = new_surface_data(*pSurface);
data->wsi.xlib.dpy = pCreateInfo->dpy;
data->wsi.xlib.window = pCreateInfo->window;
}
return result;
}
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
static VkResult overlay_CreateWaylandSurfaceKHR(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface)
{
SPDLOG_DEBUG("{}", __func__);
struct instance_data *instance_data = FIND(struct instance_data, instance);
VkResult result = instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
if (result == VK_SUCCESS) {
struct surface_data *data = new_surface_data(*pSurface);
data->wsi.wl.display = pCreateInfo->display;
data->wsi.wl.surface = pCreateInfo->surface;
}
return result;
}
#endif
static void overlay_DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator)
{
struct instance_data *instance_data = FIND(struct instance_data, instance);
struct surface_data *surface_data = FIND(struct surface_data, surface);
destroy_surface_data(surface_data);
instance_data->vtable.DestroySurfaceKHR(instance, surface, pAllocator);
}
struct overlay_draw *get_overlay_draw(struct swapchain_data *data) struct overlay_draw *get_overlay_draw(struct swapchain_data *data)
{ {
struct device_data *device_data = data->device; struct device_data *device_data = data->device;
@ -1304,10 +1383,16 @@ static void setup_swapchain_data(struct swapchain_data *data,
const VkSwapchainCreateInfoKHR *pCreateInfo) const VkSwapchainCreateInfoKHR *pCreateInfo)
{ {
struct device_data *device_data = data->device; struct device_data *device_data = data->device;
struct surface_data *surface_data = FIND(struct surface_data, pCreateInfo->surface);
data->surface_data = surface_data;
data->width = pCreateInfo->imageExtent.width; data->width = pCreateInfo->imageExtent.width;
data->height = pCreateInfo->imageExtent.height; data->height = pCreateInfo->imageExtent.height;
data->format = pCreateInfo->imageFormat; data->format = pCreateInfo->imageFormat;
#ifndef MANGOAPP
data->sw_stats.wsi = &data->surface_data->wsi;
#endif
data->imgui_context = ImGui::CreateContext(); data->imgui_context = ImGui::CreateContext();
ImGui::SetCurrentContext(data->imgui_context); ImGui::SetCurrentContext(data->imgui_context);
@ -1573,6 +1658,7 @@ static VkResult overlay_QueuePresentKHR(
VkQueue queue, VkQueue queue,
const VkPresentInfoKHR* pPresentInfo) const VkPresentInfoKHR* pPresentInfo)
{ {
bool lost_focus = false;
struct queue_data *queue_data = FIND(struct queue_data, queue); struct queue_data *queue_data = FIND(struct queue_data, queue);
/* Otherwise we need to add our overlay drawing semaphore to the list of /* Otherwise we need to add our overlay drawing semaphore to the list of
@ -1608,6 +1694,7 @@ static VkResult overlay_QueuePresentKHR(
present_info.waitSemaphoreCount = 1; present_info.waitSemaphoreCount = 1;
} }
lost_focus |= swapchain_data->sw_stats.lost_focus;
VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info); VkResult chain_result = queue_data->device->vtable.QueuePresentKHR(queue, &present_info);
if (pPresentInfo->pResults) if (pPresentInfo->pResults)
pPresentInfo->pResults[i] = chain_result; pPresentInfo->pResults[i] = chain_result;
@ -1617,9 +1704,9 @@ static VkResult overlay_QueuePresentKHR(
using namespace std::chrono_literals; using namespace std::chrono_literals;
if (fps_limit_stats.targetFrameTime > 0s){ if (fps_limit_stats.targetFrameTime > 0s || (lost_focus && fps_limit_stats.focusLossFrameTime > 0s)){
fps_limit_stats.frameStart = Clock::now(); fps_limit_stats.frameStart = Clock::now();
FpsLimiter(fps_limit_stats); FpsLimiter(fps_limit_stats, lost_focus);
fps_limit_stats.frameEnd = Clock::now(); fps_limit_stats.frameEnd = Clock::now();
} }
@ -1978,6 +2065,11 @@ static const struct {
ADD_HOOK(CreateDevice), ADD_HOOK(CreateDevice),
ADD_HOOK(DestroyDevice), ADD_HOOK(DestroyDevice),
ADD_HOOK(CreateXlibSurfaceKHR),
ADD_HOOK(CreateXcbSurfaceKHR),
ADD_HOOK(CreateWaylandSurfaceKHR),
ADD_HOOK(DestroySurfaceKHR),
ADD_HOOK(CreateInstance), ADD_HOOK(CreateInstance),
ADD_HOOK(DestroyInstance), ADD_HOOK(DestroyInstance),
#undef ADD_HOOK #undef ADD_HOOK

@ -0,0 +1,94 @@
#include <spdlog/spdlog.h>
#include <cstring>
#include "wsi_helpers.h"
#ifdef VK_USE_PLATFORM_XCB_KHR
static bool check_window_focus(xcb_connection_t * connection, xcb_window_t window)
{
auto reply = xcb_get_input_focus_reply(connection, xcb_get_input_focus(connection), nullptr);
if (reply)
{
SPDLOG_DEBUG("Window: {:08x} Focus WId: {:08x}", window, reply->focus);
bool has_focus = (window == reply->focus);
free(reply);
return has_focus;
}
// xcb_query_tree_cookie_t cookie = xcb_query_tree(connection, reply->focus);
// xcb_query_tree_reply_t *tree_reply = nullptr;
//
// if ((tree_reply = xcb_query_tree_reply(connection, cookie, nullptr))) {
// printf("root = 0x%08x\n", tree_reply->root);
// printf("parent = 0x%08x\n", tree_reply->parent);
//
// xcb_window_t *children = xcb_query_tree_children(tree_reply);
// for (int i = 0; i < xcb_query_tree_children_length(tree_reply); i++)
// printf("child window = 0x%08x\n", children[i]);
//
// free(reply);
// }
return true;
}
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
static bool check_window_focus(Display *disp, Window window)
{
if (!g_x11 || !g_x11->IsLoaded())
return true;
Window focus;
int revert_to;
if (!g_x11->XGetInputFocus(disp, &focus, &revert_to))
return true;
SPDLOG_DEBUG("Window: {:08x}, Focus: {:08x}", window, focus);
// wine vulkan surface's window is a child of "main" window?
Window w = window;
Window parent = window;
Window root = None;
Window *children;
unsigned int nchildren;
Status s;
while (parent != root) {
w = parent;
s = g_x11->XQueryTree(disp, w, &root, &parent, &children, &nchildren);
if (s)
g_x11->XFree(children);
if (w == focus || !root)
{
SPDLOG_DEBUG("we got focus");
return true;
}
SPDLOG_DEBUG(" get parent: window: {:08x}, parent: {:08x}, root: {:08x}", w, parent, root);
}
SPDLOG_DEBUG("parent: {:08x}, focus: {:08x}", w, focus);
return false;
}
#endif
bool window_has_focus(const wsi_connection* conn)
{
if (!conn)
return true;
#ifdef VK_USE_PLATFORM_XCB_KHR
if (conn->xcb.conn)
return check_window_focus(conn->xcb.conn, conn->xcb.window);
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
if (conn->xlib.dpy)
return check_window_focus(conn->xlib.dpy, conn->xlib.window);
#endif
return true;
}

@ -0,0 +1,40 @@
#pragma once
#ifdef VK_USE_PLATFORM_XLIB_KHR
#include "loaders/loader_x11.h"
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
#include <xcb/xproto.h>
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
#include <wayland-client.h>
#endif
struct wsi_connection
{
#ifdef VK_USE_PLATFORM_XCB_KHR
struct xcb {
xcb_connection_t *conn = nullptr;
xcb_window_t window = 0;
} xcb;
#endif
#ifdef VK_USE_PLATFORM_XLIB_KHR
struct xlib {
Display *dpy = nullptr;
Window window = 0;
int evmask = 0;
} xlib;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
struct wl {
wl_display *display;
wl_surface *surface;
bool has_focus;
} wl;
#endif
};
// struct wsi_connection;
// bool check_window_focus(const wsi_connection&);
Loading…
Cancel
Save