From 8282a9f3f49fcbcd375a3a08db50c1516f17b496 Mon Sep 17 00:00:00 2001 From: icex2 Date: Fri, 7 Feb 2025 14:20:27 +0100 Subject: [PATCH] TODO split to two features: imgui-bt abstraction layer + first component frame graph Summary: Test Plan: Summary: Test Plan: --- Module.mk | 2 + src/main/iidxhook-util/Module.mk | 1 + src/main/iidxhook-util/config-debug.c | 34 +++ src/main/iidxhook-util/config-debug.h | 17 ++ src/main/iidxhook1/Module.mk | 6 + src/main/iidxhook1/dllmain.c | 22 ++ src/main/iidxhook2/Module.mk | 6 + src/main/iidxhook2/dllmain.c | 22 ++ src/main/iidxhook3/Module.mk | 7 + src/main/iidxhook3/dllmain.c | 22 ++ src/main/iidxhook4-cn/Module.mk | 6 + src/main/iidxhook4-cn/dllmain.c | 22 ++ src/main/iidxhook4/Module.mk | 6 + src/main/iidxhook4/dllmain.c | 22 ++ src/main/iidxhook5-cn/Module.mk | 6 + src/main/iidxhook5-cn/dllmain.c | 22 ++ src/main/iidxhook5/Module.mk | 6 + src/main/iidxhook5/dllmain.c | 22 ++ src/main/iidxhook6/Module.mk | 6 + src/main/iidxhook6/dllmain.c | 22 ++ src/main/iidxhook7/Module.mk | 5 + src/main/iidxhook7/dllmain.c | 26 ++ src/main/iidxhook8/Module.mk | 8 +- src/main/iidxhook8/dllmain.c | 21 ++ src/main/imgui-bt/Module.mk | 10 + .../{imgui/cimgui-bt.h => imgui-bt/cimgui.h} | 6 +- src/main/imgui-bt/component.h | 12 + src/main/imgui-bt/imgui-d3d9-hook.c | 143 ++++++++++ src/main/imgui-bt/imgui-d3d9-hook.h | 13 + src/main/imgui-debug/Module.mk | 10 + src/main/imgui-debug/frame-perf-graph.c | 258 ++++++++++++++++++ src/main/imgui-debug/frame-perf-graph.h | 10 + src/main/imgui-debug/time-history.c | 63 +++++ src/main/imgui-debug/time-history.h | 23 ++ src/main/util/Module.mk | 1 + src/main/util/proc.c | 251 ++++++++++++++--- src/main/util/proc.h | 33 ++- 37 files changed, 1122 insertions(+), 50 deletions(-) create mode 100644 src/main/iidxhook-util/config-debug.c create mode 100644 src/main/iidxhook-util/config-debug.h create mode 100644 src/main/imgui-bt/Module.mk rename src/main/{imgui/cimgui-bt.h => imgui-bt/cimgui.h} (50%) create mode 100644 src/main/imgui-bt/component.h create mode 100644 src/main/imgui-bt/imgui-d3d9-hook.c create mode 100644 src/main/imgui-bt/imgui-d3d9-hook.h create mode 100644 src/main/imgui-debug/Module.mk create mode 100644 src/main/imgui-debug/frame-perf-graph.c create mode 100644 src/main/imgui-debug/frame-perf-graph.h create mode 100644 src/main/imgui-debug/time-history.c create mode 100644 src/main/imgui-debug/time-history.h diff --git a/Module.mk b/Module.mk index 4ba926c..170ac9e 100644 --- a/Module.mk +++ b/Module.mk @@ -160,6 +160,8 @@ include src/main/iidxio-ezusb2/Module.mk include src/main/iidxio/Module.mk include src/main/iidxiotest/Module.mk include src/main/imgui/Module.mk +include src/main/imgui-bt/Module.mk +include src/main/imgui-debug/Module.mk include src/main/inject/Module.mk include src/main/jbio-magicbox/Module.mk include src/main/jbio-p4io/Module.mk diff --git a/src/main/iidxhook-util/Module.mk b/src/main/iidxhook-util/Module.mk index 92fe44d..1e5bbbe 100644 --- a/src/main/iidxhook-util/Module.mk +++ b/src/main/iidxhook-util/Module.mk @@ -7,6 +7,7 @@ src_iidxhook-util := \ acio.c \ chart-patch.c \ clock.c \ + config-debug.c \ config-eamuse.c \ config-ezusb.c \ config-gfx.c \ diff --git a/src/main/iidxhook-util/config-debug.c b/src/main/iidxhook-util/config-debug.c new file mode 100644 index 0000000..85a031e --- /dev/null +++ b/src/main/iidxhook-util/config-debug.c @@ -0,0 +1,34 @@ +#include "cconfig/cconfig-util.h" + +#include "iidxhook-util/config-debug.h" + +#include "util/log.h" + +#define IIDXHOOK_CONFIG_DEBUG_ENABLE_FRAME_PERF_GRAPH_KEY "debug.enable_frame_perf_graph" + +#define IIDXHOOK_CONFIG_DEBUG_DEFAULT_ENABLE_FRAME_PERF_GRAPH_VALUE false + +void iidxhook_config_debug_init(struct cconfig *config) +{ + cconfig_util_set_bool( + config, + IIDXHOOK_CONFIG_DEBUG_ENABLE_FRAME_PERF_GRAPH_KEY, + IIDXHOOK_CONFIG_DEBUG_DEFAULT_ENABLE_FRAME_PERF_GRAPH_VALUE, + "Enable frame performance graph overlay"); +} + +void iidxhook_config_debug_get( + struct iidxhook_config_debug *config_debug, struct cconfig *config) +{ + if (!cconfig_util_get_bool( + config, + IIDXHOOK_CONFIG_DEBUG_ENABLE_FRAME_PERF_GRAPH_KEY, + &config_debug->enable_frame_perf_graph, + IIDXHOOK_CONFIG_DEBUG_DEFAULT_ENABLE_FRAME_PERF_GRAPH_VALUE)) { + log_warning( + "Invalid value for key '%s' specified, fallback " + "to default '%d'", + IIDXHOOK_CONFIG_DEBUG_ENABLE_FRAME_PERF_GRAPH_KEY, + IIDXHOOK_CONFIG_DEBUG_DEFAULT_ENABLE_FRAME_PERF_GRAPH_VALUE); + } +} diff --git a/src/main/iidxhook-util/config-debug.h b/src/main/iidxhook-util/config-debug.h new file mode 100644 index 0000000..f97568e --- /dev/null +++ b/src/main/iidxhook-util/config-debug.h @@ -0,0 +1,17 @@ +#ifndef IIDXHOOK_CONFIG_DEBUG_H +#define IIDXHOOK_CONFIG_DEBUG_H + +#include + +#include "cconfig/cconfig.h" + +struct iidxhook_config_debug { + bool enable_frame_perf_graph; +}; + +void iidxhook_config_debug_init(struct cconfig *config); + +void iidxhook_config_debug_get( + struct iidxhook_config_debug *config_debug, struct cconfig *config); + +#endif \ No newline at end of file diff --git a/src/main/iidxhook1/Module.mk b/src/main/iidxhook1/Module.mk index fcfad98..e692987 100644 --- a/src/main/iidxhook1/Module.mk +++ b/src/main/iidxhook1/Module.mk @@ -3,6 +3,9 @@ dlls += iidxhook1 ldflags_iidxhook1 := \ -lws2_32 \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ libs_iidxhook1 := \ iidxhook-util \ @@ -18,6 +21,9 @@ libs_iidxhook1 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook1 := \ config-iidxhook1.c \ diff --git a/src/main/iidxhook1/dllmain.c b/src/main/iidxhook1/dllmain.c index a3a4a35..5340909 100644 --- a/src/main/iidxhook1/dllmain.c +++ b/src/main/iidxhook1/dllmain.c @@ -27,6 +27,7 @@ #include "iidxhook-util/chart-patch.h" #include "iidxhook-util/clock.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-eamuse.h" #include "iidxhook-util/config-ezusb.h" #include "iidxhook-util/config-gfx.h" @@ -41,6 +42,10 @@ #include "iidxhook1/ezusb-mon.h" #include "iidxhook1/log-ezusb.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "util/defs.h" #include "util/log.h" #include "util/thread.h" @@ -53,6 +58,7 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler }; static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD); @@ -68,6 +74,17 @@ static const struct hook_symbol init_hook_syms[] = { }, }; +static void iidxhook1_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook1_setup_d3d9_hooks( const struct iidxhook_config_gfx *config_gfx, const struct iidxhook_config_iidxhook1 *config_iidxhook1) @@ -125,6 +142,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_util_config_ezusb config_ezusb; struct iidxhook_util_config_eamuse config_eamuse; struct iidxhook_config_gfx config_gfx; @@ -144,6 +162,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_util_config_ezusb_init(config); iidxhook_util_config_eamuse_init(config); iidxhook_config_gfx_init(config); @@ -159,6 +178,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_util_config_ezusb_get(&config_ezusb, config); iidxhook_util_config_eamuse_get(&config_eamuse, config); iidxhook_config_gfx_get(&config_gfx, config); @@ -202,6 +222,8 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) settings_hook_set_path(config_misc.settings_path); } + iidxhook1_setup_imgui_debug_components(&config_debug); + /* Direct3D and USER32 hooks */ iidxhook1_setup_d3d9_hooks(&config_gfx, &config_iidxhook1); diff --git a/src/main/iidxhook2/Module.mk b/src/main/iidxhook2/Module.mk index c9fd438..292f496 100644 --- a/src/main/iidxhook2/Module.mk +++ b/src/main/iidxhook2/Module.mk @@ -3,6 +3,9 @@ avsdlls += iidxhook2 ldflags_iidxhook2 := \ -lws2_32 \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ libs_iidxhook2 := \ iidxhook-util \ @@ -18,6 +21,9 @@ libs_iidxhook2 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook2 := \ config-iidxhook2.c \ diff --git a/src/main/iidxhook2/dllmain.c b/src/main/iidxhook2/dllmain.c index 25a76ed..f85ddd7 100644 --- a/src/main/iidxhook2/dllmain.c +++ b/src/main/iidxhook2/dllmain.c @@ -29,6 +29,7 @@ #include "iidxhook-util/acio.h" #include "iidxhook-util/chart-patch.h" #include "iidxhook-util/clock.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-eamuse.h" #include "iidxhook-util/config-ezusb.h" #include "iidxhook-util/config-gfx.h" @@ -41,6 +42,10 @@ #include "iidxhook2/config-iidxhook2.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "util/log.h" #include "util/thread.h" @@ -52,6 +57,7 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD); @@ -65,6 +71,17 @@ static const struct hook_symbol init_hook_syms[] = { .link = (void **) &real_OpenProcess}, }; +static void iidxhook2_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook2_setup_d3d9_hooks( const struct iidxhook_config_gfx *config_gfx, const struct iidxhook_config_iidxhook2 *config_iidxhook2) @@ -122,6 +139,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_util_config_ezusb config_ezusb; struct iidxhook_util_config_eamuse config_eamuse; struct iidxhook_config_gfx config_gfx; @@ -141,6 +159,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_util_config_ezusb_init(config); iidxhook_util_config_eamuse_init(config); iidxhook_config_gfx_init(config); @@ -156,6 +175,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_util_config_ezusb_get(&config_ezusb, config); iidxhook_util_config_eamuse_get(&config_eamuse, config); iidxhook_config_gfx_get(&config_gfx, config); @@ -194,6 +214,8 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) settings_hook_set_path(config_misc.settings_path); } + iidxhook2_setup_imgui_debug_components(&config_debug); + /* Direct3D and USER32 hooks */ iidxhook2_setup_d3d9_hooks(&config_gfx, &config_iidxhook2); diff --git a/src/main/iidxhook3/Module.mk b/src/main/iidxhook3/Module.mk index e328bec..a79b2e9 100644 --- a/src/main/iidxhook3/Module.mk +++ b/src/main/iidxhook3/Module.mk @@ -3,9 +3,13 @@ avsdlls += iidxhook3 ldflags_iidxhook3 := \ -lws2_32 \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ libs_iidxhook3 := \ iidxhook-util \ + iidxhook-d3d9 \ ezusb-emu \ ezusb-iidx-16seg-emu \ ezusb2-emu \ @@ -20,6 +24,9 @@ libs_iidxhook3 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook3 := \ dllmain.c \ diff --git a/src/main/iidxhook3/dllmain.c b/src/main/iidxhook3/dllmain.c index b2e0e41..092b9fe 100644 --- a/src/main/iidxhook3/dllmain.c +++ b/src/main/iidxhook3/dllmain.c @@ -30,6 +30,7 @@ #include "iidxhook-util/acio.h" #include "iidxhook-util/chart-patch.h" #include "iidxhook-util/clock.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-eamuse.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-misc.h" @@ -38,6 +39,10 @@ #include "iidxhook-util/eamuse.h" #include "iidxhook-util/settings.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "security/rp-sign-key.h" #include "util/log.h" @@ -52,6 +57,7 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static HANDLE STDCALL my_OpenProcess(DWORD, BOOL, DWORD); @@ -64,6 +70,17 @@ static const struct hook_symbol init_hook_syms[] = { .link = (void **) &real_OpenProcess}, }; +static void iidxhook3_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook3_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -120,6 +137,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_util_config_eamuse config_eamuse; struct iidxhook_config_gfx config_gfx; struct iidxhook_config_misc config_misc; @@ -137,6 +155,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_util_config_eamuse_init(config); iidxhook_config_gfx_init(config); iidxhook_config_misc_init(config); @@ -150,6 +169,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_util_config_eamuse_get(&config_eamuse, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_misc_get(&config_misc, config); @@ -187,6 +207,8 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) settings_hook_set_path(config_misc.settings_path); } + iidxhook3_setup_imgui_debug_components(&config_debug); + /* Direct3D and USER32 hooks */ iidxhook3_setup_d3d9_hooks(&config_gfx); diff --git a/src/main/iidxhook4-cn/Module.mk b/src/main/iidxhook4-cn/Module.mk index 0f7bcee..6cd0edf 100644 --- a/src/main/iidxhook4-cn/Module.mk +++ b/src/main/iidxhook4-cn/Module.mk @@ -3,6 +3,9 @@ avsdlls += iidxhook4-cn ldflags_iidxhook4-cn := \ -liphlpapi \ -lws2_32 \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook4-cn := \ avs \ @@ -20,6 +23,9 @@ libs_iidxhook4-cn := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook4-cn := \ avs-boot.c \ diff --git a/src/main/iidxhook4-cn/dllmain.c b/src/main/iidxhook4-cn/dllmain.c index ea2f42a..072e266 100644 --- a/src/main/iidxhook4-cn/dllmain.c +++ b/src/main/iidxhook4-cn/dllmain.c @@ -25,6 +25,7 @@ #include "iidxhook4-cn/path.h" #include "iidxhook-util/chart-patch.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-eamuse.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" @@ -33,6 +34,10 @@ #include "iidxhook-util/d3d9.h" #include "iidxhook-util/settings.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "security/rp-sign-key.h" #include "imports/avs.h" @@ -51,6 +56,7 @@ static bool iidxhook_init_check; static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static const struct hook_symbol init_hook_syms[] = { @@ -61,6 +67,17 @@ static const struct hook_symbol init_hook_syms[] = { static struct iidxhook_config_io config_io; +static void iidxhook4_cn_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook4_cn_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -117,6 +134,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_util_config_eamuse config_eamuse; struct iidxhook_config_gfx config_gfx; struct iidxhook_config_sec config_sec; @@ -134,6 +152,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_util_config_eamuse_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); @@ -148,6 +167,7 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_util_config_eamuse_get(&config_eamuse, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); @@ -174,6 +194,8 @@ my_OpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId) &config_sec.black_plug_mcode); ezusb_iidx_emu_node_security_plug_set_pcbid(&config_eamuse.pcbid); + iidxhook4_cn_setup_imgui_debug_components(&config_debug); + iidxhook4_cn_setup_d3d9_hooks(&config_gfx); if (strlen(config_misc.settings_path) > 0) { diff --git a/src/main/iidxhook4/Module.mk b/src/main/iidxhook4/Module.mk index 40f40b0..184a3b1 100644 --- a/src/main/iidxhook4/Module.mk +++ b/src/main/iidxhook4/Module.mk @@ -2,6 +2,9 @@ avsdlls += iidxhook4 ldflags_iidxhook4 := \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook4 := \ avs \ @@ -22,6 +25,9 @@ libs_iidxhook4 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook4 := \ dllmain.c \ diff --git a/src/main/iidxhook4/dllmain.c b/src/main/iidxhook4/dllmain.c index d7993dd..afe3149 100644 --- a/src/main/iidxhook4/dllmain.c +++ b/src/main/iidxhook4/dllmain.c @@ -27,6 +27,7 @@ #include "iidxhook-util/acio.h" #include "iidxhook-util/chart-patch.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" #include "iidxhook-util/config-misc.h" @@ -34,6 +35,10 @@ #include "iidxhook-util/log-server.h" #include "iidxhook-util/settings.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "imports/avs.h" #include "util/log.h" @@ -48,10 +53,22 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static struct iidxhook_config_io config_io; +static void iidxhook4_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook4_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -101,6 +118,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_config_gfx config_gfx; struct iidxhook_config_misc config_misc; @@ -111,6 +129,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); iidxhook_config_misc_init(config); @@ -124,6 +143,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); iidxhook_config_misc_get(&config_misc, config); @@ -133,6 +153,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info(IIDXHOOK4_INFO_HEADER); log_info("Initializing iidxhook..."); + iidxhook4_setup_imgui_debug_components(&config_debug); + iidxhook4_setup_d3d9_hooks(&config_gfx); if (strlen(config_misc.settings_path) > 0) { diff --git a/src/main/iidxhook5-cn/Module.mk b/src/main/iidxhook5-cn/Module.mk index feea3d4..351bec1 100644 --- a/src/main/iidxhook5-cn/Module.mk +++ b/src/main/iidxhook5-cn/Module.mk @@ -3,6 +3,9 @@ avsdlls += iidxhook5-cn ldflags_iidxhook5-cn := \ -liphlpapi \ -lws2_32 \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook5-cn := \ avs \ @@ -20,6 +23,9 @@ libs_iidxhook5-cn := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook5-cn := \ avs-boot.c \ diff --git a/src/main/iidxhook5-cn/dllmain.c b/src/main/iidxhook5-cn/dllmain.c index 711c906..aae9a07 100644 --- a/src/main/iidxhook5-cn/dllmain.c +++ b/src/main/iidxhook5-cn/dllmain.c @@ -25,6 +25,7 @@ #include "iidxhook5-cn/avs-boot.h" #include "iidxhook5-cn/path.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-eamuse.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" @@ -33,6 +34,10 @@ #include "iidxhook-util/d3d9.h" #include "iidxhook-util/settings.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "security/rp-sign-key.h" #include "imports/avs.h" @@ -51,6 +56,7 @@ static bool iidxhook_init_check; static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static const struct hook_symbol init_hook_user32_syms[] = { @@ -61,6 +67,17 @@ static const struct hook_symbol init_hook_user32_syms[] = { static struct iidxhook_config_io config_io; +static void iidxhook5_cn_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook5_cn_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -97,6 +114,7 @@ static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_util_config_eamuse config_eamuse; struct iidxhook_config_gfx config_gfx; struct iidxhook_config_sec config_sec; @@ -114,6 +132,7 @@ static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_util_config_eamuse_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); @@ -128,6 +147,7 @@ static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_util_config_eamuse_get(&config_eamuse, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); @@ -154,6 +174,8 @@ static ATOM WINAPI my_RegisterClassA(const WNDCLASSA *lpWndClass) &config_sec.black_plug_mcode); ezusb_iidx_emu_node_security_plug_set_pcbid(&config_eamuse.pcbid); + iidxhook5_cn_setup_imgui_debug_components(&config_debug); + iidxhook5_cn_setup_d3d9_hooks(&config_gfx); if (strlen(config_misc.settings_path) > 0) { diff --git a/src/main/iidxhook5/Module.mk b/src/main/iidxhook5/Module.mk index 78ea307..7f0274a 100644 --- a/src/main/iidxhook5/Module.mk +++ b/src/main/iidxhook5/Module.mk @@ -2,6 +2,9 @@ avsdlls += iidxhook5 ldflags_iidxhook5 := \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook5 := \ avs \ @@ -22,6 +25,9 @@ libs_iidxhook5 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook5 := \ dllmain.c \ diff --git a/src/main/iidxhook5/dllmain.c b/src/main/iidxhook5/dllmain.c index 268bf39..dbee76d 100644 --- a/src/main/iidxhook5/dllmain.c +++ b/src/main/iidxhook5/dllmain.c @@ -27,6 +27,7 @@ #include "iidxhook-util/acio.h" #include "iidxhook-util/chart-patch.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" #include "iidxhook-util/config-misc.h" @@ -34,6 +35,10 @@ #include "iidxhook-util/log-server.h" #include "iidxhook-util/settings.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "imports/avs.h" #include "util/log.h" @@ -50,10 +55,22 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static struct iidxhook_config_io config_io; +static void iidxhook5_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook5_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -103,6 +120,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_config_gfx config_gfx; struct iidxhook_config_misc config_misc; @@ -113,6 +131,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); iidxhook_config_misc_init(config); @@ -126,6 +145,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); iidxhook_config_misc_get(&config_misc, config); @@ -135,6 +155,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info(IIDXHOOK5_INFO_HEADER); log_info("Initializing iidxhook..."); + iidxhook5_setup_imgui_debug_components(&config_debug); + iidxhook5_setup_d3d9_hooks(&config_gfx); if (strlen(config_misc.settings_path) > 0) { diff --git a/src/main/iidxhook6/Module.mk b/src/main/iidxhook6/Module.mk index 7fda87b..d664a1e 100644 --- a/src/main/iidxhook6/Module.mk +++ b/src/main/iidxhook6/Module.mk @@ -2,6 +2,9 @@ avsdlls += iidxhook6 ldflags_iidxhook6 := \ -liphlpapi \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook6 := \ avs \ @@ -23,6 +26,9 @@ libs_iidxhook6 := \ cconfig \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook6 := \ dllmain.c \ diff --git a/src/main/iidxhook6/dllmain.c b/src/main/iidxhook6/dllmain.c index b4ca65a..7ecbefc 100644 --- a/src/main/iidxhook6/dllmain.c +++ b/src/main/iidxhook6/dllmain.c @@ -28,11 +28,16 @@ #include "iidxhook-d3d9/bb-scale-hd.h" #include "iidxhook-util/acio.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" #include "iidxhook-util/d3d9.h" #include "iidxhook-util/log-server.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "imports/avs.h" #include "util/log.h" @@ -48,10 +53,22 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_d3d9_bb_scale_hd_d3d9_irp_handler, iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static struct iidxhook_config_io config_io; +static void iidxhook6_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook6_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -87,6 +104,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_config_gfx config_gfx; log_server_init(); @@ -96,6 +114,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); @@ -108,6 +127,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); @@ -116,6 +136,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info(IIDXHOOK6_INFO_HEADER); log_info("Initializing iidxhook..."); + iidxhook6_setup_imgui_debug_components(&config_debug); + iidxhook6_setup_d3d9_hooks(&config_gfx); if (!config_io.disable_io_emu) { diff --git a/src/main/iidxhook7/Module.mk b/src/main/iidxhook7/Module.mk index a40366a..4c592a4 100644 --- a/src/main/iidxhook7/Module.mk +++ b/src/main/iidxhook7/Module.mk @@ -3,6 +3,8 @@ avsdlls += iidxhook7 ldflags_iidxhook7 := \ -liphlpapi \ -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook7 := \ avs \ @@ -24,6 +26,9 @@ libs_iidxhook7 := \ iidxio \ util \ ezusb \ + imgui-bt \ + imgui-debug \ + imgui \ src_iidxhook7 := \ dllmain.c \ diff --git a/src/main/iidxhook7/dllmain.c b/src/main/iidxhook7/dllmain.c index af948f6..80fb158 100644 --- a/src/main/iidxhook7/dllmain.c +++ b/src/main/iidxhook7/dllmain.c @@ -28,11 +28,16 @@ #include "iidxhook-d3d9/bb-scale-hd.h" #include "iidxhook-util/acio.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/config-io.h" #include "iidxhook-util/d3d9.h" #include "iidxhook-util/log-server.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "imports/avs.h" #include "util/log.h" @@ -48,10 +53,22 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_d3d9_bb_scale_hd_d3d9_irp_handler, iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; static struct iidxhook_config_io config_io; +static void iidxhook7_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} + static void iidxhook7_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -87,6 +104,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_config_gfx config_gfx; log_server_init(); @@ -96,6 +114,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_config_gfx_init(config); iidxhook_config_io_init(config); @@ -108,6 +127,11 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) exit(EXIT_FAILURE); } + iidxhook_config_debug_init(config); + iidxhook_config_gfx_init(config); + iidxhook_config_io_init(config); + + iidxhook_config_debug_get(&config_debug, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook_config_io_get(&config_io, config); @@ -116,6 +140,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info(IIDXHOOK7_INFO_HEADER); log_info("Initializing iidxhook..."); + iidxhook7_setup_imgui_debug_components(&config_debug); + iidxhook7_setup_d3d9_hooks(&config_gfx); if (!config_io.disable_io_emu) { diff --git a/src/main/iidxhook8/Module.mk b/src/main/iidxhook8/Module.mk index e71c8c2..954191c 100644 --- a/src/main/iidxhook8/Module.mk +++ b/src/main/iidxhook8/Module.mk @@ -7,6 +7,9 @@ ldflags_iidxhook8 := \ -lmf \ -lmfplat \ -lole32 \ + -ld3d9 \ + -ldwmapi\ + -lgdi32 \ deplibs_iidxhook8 := \ avs \ @@ -24,7 +27,10 @@ libs_iidxhook8 := \ cconfig \ util \ eamio \ - + imgui-bt \ + imgui-debug \ + imgui \ + src_iidxhook8 := \ config-io.c \ dllmain.c \ diff --git a/src/main/iidxhook8/dllmain.c b/src/main/iidxhook8/dllmain.c index 13509be..d1c95ab 100644 --- a/src/main/iidxhook8/dllmain.c +++ b/src/main/iidxhook8/dllmain.c @@ -21,10 +21,15 @@ #include "iidxhook-d3d9/bb-scale-hd.h" #include "iidxhook-util/acio.h" +#include "iidxhook-util/config-debug.h" #include "iidxhook-util/config-gfx.h" #include "iidxhook-util/d3d9.h" #include "iidxhook-util/log-server.h" +#include "imgui-bt/imgui-d3d9-hook.h" + +#include "imgui-debug/frame-perf-graph.h" + #include "bio2emu-iidx/bi2a.h" #include "bio2emu/emu.h" @@ -47,8 +52,19 @@ static const hook_d3d9_irp_handler_t iidxhook_d3d9_handlers[] = { iidxhook_d3d9_bb_scale_hd_d3d9_irp_handler, iidxhook_util_d3d9_irp_handler, + imgui_hook_d3d9_irp_handler, }; +static void iidxhook8_setup_imgui_debug_components(const struct iidxhook_config_debug *config_debug) +{ + imgui_bt_component_t debug_frame_graph_component; + + if (config_debug->enable_frame_perf_graph) { + imgui_debug_frame_perf_graph_init(60.0f, &debug_frame_graph_component); + + imgui_d3d9_hook_init(&debug_frame_graph_component, 1); + } +} static void iidxhook8_setup_d3d9_hooks(const struct iidxhook_config_gfx *config_gfx) { @@ -93,6 +109,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) { struct cconfig *config; + struct iidxhook_config_debug config_debug; struct iidxhook_config_gfx config_gfx; // log_server_init is required due to IO occuring in a non avs_thread @@ -104,6 +121,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) config = cconfig_init(); + iidxhook_config_debug_init(config); iidxhook_config_gfx_init(config); iidxhook8_config_io_init(config); camhook_config_cam_init(config, 2); @@ -117,6 +135,7 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) exit(EXIT_FAILURE); } + iidxhook_config_debug_get(&config_debug, config); iidxhook_config_gfx_get(&config_gfx, config); iidxhook8_config_io_get(&iidxhook8_config_io, config); camhook_config_cam_get(&config_cam, config, 2); @@ -126,6 +145,8 @@ static bool my_dll_entry_init(char *sidcode, struct property_node *param) log_info(IIDXHOOK8_INFO_HEADER); log_info("Initializing iidxhook..."); + iidxhook8_setup_imgui_debug_components(&config_debug); + iidxhook8_setup_d3d9_hooks(&config_gfx); /* Start up IIDXIO.DLL */ diff --git a/src/main/imgui-bt/Module.mk b/src/main/imgui-bt/Module.mk new file mode 100644 index 0000000..fcf1676 --- /dev/null +++ b/src/main/imgui-bt/Module.mk @@ -0,0 +1,10 @@ +libs += imgui-bt + +libs_imgui-bt := \ + hook \ + hooklib \ + util \ + imgui \ + +src_imgui-bt := \ + imgui-d3d9-hook.c \ diff --git a/src/main/imgui/cimgui-bt.h b/src/main/imgui-bt/cimgui.h similarity index 50% rename from src/main/imgui/cimgui-bt.h rename to src/main/imgui-bt/cimgui.h index fe06ad6..75b8f3e 100644 --- a/src/main/imgui/cimgui-bt.h +++ b/src/main/imgui-bt/cimgui.h @@ -1,7 +1,7 @@ -#ifndef IMGUI_CIMGUI_BT_H -#define IMGUI_CIMGUI_BT_H +#ifndef IMGUI_BT_CIMGUI_H +#define IMGUI_BT_CIMGUI_H -// Comprehnsive header file for including cimgui correctly for integration in this project +// Comprehensive header file for including cimgui correctly for integration in this project #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS #include "imgui/cimgui.h" #include "imgui/cimgui_impl_dx9.h" diff --git a/src/main/imgui-bt/component.h b/src/main/imgui-bt/component.h new file mode 100644 index 0000000..fc479a8 --- /dev/null +++ b/src/main/imgui-bt/component.h @@ -0,0 +1,12 @@ +#ifndef IMGUI_BT_COMPONENT_H +#define IMGUI_BT_COMPONENT_H + +#include "imgui-bt/cimgui.h" + +typedef void (*imgui_bt_component_frame_update_t)(ImGuiContext *ctx); + +typedef struct imgui_bt_component { + imgui_bt_component_frame_update_t frame_update; +} imgui_bt_component_t; + +#endif diff --git a/src/main/imgui-bt/imgui-d3d9-hook.c b/src/main/imgui-bt/imgui-d3d9-hook.c new file mode 100644 index 0000000..6f230fc --- /dev/null +++ b/src/main/imgui-bt/imgui-d3d9-hook.c @@ -0,0 +1,143 @@ +#define LOG_MODULE "imgui-d3d9-hook" + +#include "hook/d3d9.h" +#include "hook/table.h" + +#include "imgui-bt/cimgui.h" +#include "imgui-bt/component.h" + +#include "util/defs.h" +#include "util/log.h" +#include "util/mem.h" + +typedef LRESULT WINAPI (*RegisterClassA_t)(WNDCLASSA *lpwcx); +typedef LRESULT WINAPI (*WndProc_t)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static LRESULT WINAPI _imgui_d3d9_hook_RegisterClassA(WNDCLASSA *lpwcx); + +static bool _imgui_d3d9_hook_initialized; +static ImGuiContext *_imgui_d3d9_hook_imgui_ctx; +static RegisterClassA_t _imgui_d3d9_hook_original_RegisterClassA; +static WndProc_t _imgui_d3d9_hook_original_wndproc; +static imgui_bt_component_t *_imgui_d3d9_hook_components; +static size_t _imgui_d3d9_hook_component_count; + +static const struct hook_symbol _imgui_d3d9_hook_syms[] = { + {.name = "RegisterClassA", + .patch = _imgui_d3d9_hook_RegisterClassA, + .link = (void **) &_imgui_d3d9_hook_original_RegisterClassA}, +}; + +CIMGUI_API LRESULT igImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static LRESULT WINAPI _imgui_d3d9_hook_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LRESULT result; + + result = igImplWin32_WndProcHandler(hWnd, msg, wParam, lParam); + + if (result) { + return result; + } + + return _imgui_d3d9_hook_original_wndproc(hWnd, msg, wParam, lParam); +} + +static LRESULT WINAPI _imgui_d3d9_hook_RegisterClassA(WNDCLASSA *lpwcx) +{ + log_info("Swapping out WndProc handler for wrapper handler in RegisterClassA %s", lpwcx->lpszClassName); + + _imgui_d3d9_hook_original_wndproc = lpwcx->lpfnWndProc; + lpwcx->lpfnWndProc = _imgui_d3d9_hook_WndProc; + + return _imgui_d3d9_hook_original_RegisterClassA(lpwcx); +} + +void imgui_d3d9_hook_init(const imgui_bt_component_t *components, size_t component_count) +{ + ImGuiIO *io; + ImGuiStyle* style; + + log_assert(components); + log_assert(component_count > 0); + + _imgui_d3d9_hook_components = (imgui_bt_component_t *) xmalloc(component_count * sizeof(imgui_bt_component_t)); + memcpy(_imgui_d3d9_hook_components, components, component_count * sizeof(imgui_bt_component_t)); + _imgui_d3d9_hook_component_count = component_count; + + _imgui_d3d9_hook_imgui_ctx = igCreateContext(NULL); + io = igGetIO(); + + io->ConfigFlags = ImGuiConfigFlags_NavEnableKeyboard + | ImGuiConfigFlags_DockingEnable + | ImGuiConfigFlags_ViewportsEnable; + + io->MouseDrawCursor = true; + io->IniFilename = NULL; + io->FontAllowUserScaling = true; + + hook_table_apply(NULL, "user32.dll", _imgui_d3d9_hook_syms, lengthof(_imgui_d3d9_hook_syms)); + + // Setup style + style = igGetStyle(); + style->Colors[ImGuiCol_WindowBg] = (ImVec4){0.0f, 0.0f, 0.0f, 1.0f}; + style->Colors[ImGuiCol_PlotLines] = (ImVec4){1.0f, 1.0f, 0.0f, 1.0f}; + + _imgui_d3d9_hook_initialized = true; +} + +void imgui_d3d9_hook_fini() +{ + hook_table_revert(NULL, "user32.dll", _imgui_d3d9_hook_syms, lengthof(_imgui_d3d9_hook_syms)); + + igImplDX9_Shutdown(); + igImplWin32_Shutdown(); + igDestroyContext(NULL); + + _imgui_d3d9_hook_initialized = false; +} + +HRESULT imgui_hook_d3d9_irp_handler(struct hook_d3d9_irp *irp) +{ + HRESULT hr; + + log_assert(irp); + + if (!_imgui_d3d9_hook_initialized) { + return hook_d3d9_irp_invoke_next(irp); + } + + switch (irp->op) { + case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE: + hr = hook_d3d9_irp_invoke_next(irp); + + if (hr == S_OK) { + igImplWin32_Init(irp->args.ctx_create_device.hwnd); + igImplDX9_Init(*irp->args.ctx_create_device.pdev); + } + + return hr; + + case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE: + igImplDX9_NewFrame(); + igImplWin32_NewFrame(); + igNewFrame(); + + for (size_t i = 0; i < _imgui_d3d9_hook_component_count; i++) { + _imgui_d3d9_hook_components[i].frame_update(_imgui_d3d9_hook_imgui_ctx); + } + + return hook_d3d9_irp_invoke_next(irp); + + case HOOK_D3D9_IRP_OP_DEV_END_SCENE: + igRender(); + igImplDX9_RenderDrawData(igGetDrawData()); + + return hook_d3d9_irp_invoke_next(irp); + + default: + return hook_d3d9_irp_invoke_next(irp); + } + + log_fatal("Illegal state"); +} \ No newline at end of file diff --git a/src/main/imgui-bt/imgui-d3d9-hook.h b/src/main/imgui-bt/imgui-d3d9-hook.h new file mode 100644 index 0000000..59e0f0e --- /dev/null +++ b/src/main/imgui-bt/imgui-d3d9-hook.h @@ -0,0 +1,13 @@ +#ifndef IMGUI_D3D9_HOOK_H +#define IMGUI_D3D9_HOOK_H + +#include "hook/d3d9.h" + +#include "imgui-bt/component.h" + +void imgui_d3d9_hook_init(const imgui_bt_component_t *components, size_t component_count); +void imgui_d3d9_hook_fini(); + +HRESULT imgui_hook_d3d9_irp_handler(struct hook_d3d9_irp *irp); + +#endif \ No newline at end of file diff --git a/src/main/imgui-debug/Module.mk b/src/main/imgui-debug/Module.mk new file mode 100644 index 0000000..5a4073f --- /dev/null +++ b/src/main/imgui-debug/Module.mk @@ -0,0 +1,10 @@ +libs += imgui-debug + +libs_imgui-debug := \ + imgui-bt \ + imgui \ + util \ + +src_imgui-debug := \ + frame-perf-graph.c \ + time-history.c \ diff --git a/src/main/imgui-debug/frame-perf-graph.c b/src/main/imgui-debug/frame-perf-graph.c new file mode 100644 index 0000000..9228f96 --- /dev/null +++ b/src/main/imgui-debug/frame-perf-graph.c @@ -0,0 +1,258 @@ +#include + +#include "imgui-bt/cimgui.h" + +#include "imgui-debug/frame-perf-graph.h" +#include "imgui-debug/time-history.h" + +#include "util/log.h" + +typedef struct imgui_debug_frame_perf_graph { + float target_time_ms; + float y_axis_min_time_ms; + float y_axis_max_time_ms; +} imgui_debug_frame_perf_graph_t; + +static const ImVec2 WINDOW_MIN_SIZE = {320, 240}; + +static imgui_debug_time_history_t _imgui_debug_frame_perf_graph_history; +static imgui_debug_frame_perf_graph_t _imgui_debug_frame_perf_graph; + +static void _imgui_debug_frame_perf_graph_draw( + imgui_debug_frame_perf_graph_t *graph, + const imgui_debug_time_history_t *history) +{ + float current_value; + ImVec2 window_size; + static bool show_labels = true; + static bool show_target_line = true; + static bool show_avg_line = true; + + log_assert(history); + + current_value = imgui_debug_time_history_recent_value_get(history); + + igSetNextWindowSize(WINDOW_MIN_SIZE, ImGuiCond_FirstUseEver); + igSetNextWindowSizeConstraints(WINDOW_MIN_SIZE, igGetIO()->DisplaySize, NULL, NULL); + + igBegin("Frame Time Graph", NULL, ImGuiWindowFlags_MenuBar); + + // Add menu bar + if (igBeginMenuBar()) { + if (igBeginMenu("Settings", true)) { + igPushItemWidth(110); + + float min_time_slider = graph->y_axis_min_time_ms; + float max_time_slider = graph->y_axis_max_time_ms; + float target_time_input = graph->target_time_ms; + + if (igDragFloat("y-axis min time (ms)", &min_time_slider, 0.1f, 0.1f, max_time_slider - 0.1f, "%.1f", ImGuiSliderFlags_None)) { + graph->y_axis_min_time_ms = min_time_slider; + } + + if (igDragFloat("y-axis max time (ms)", &max_time_slider, 0.1f, min_time_slider + 0.1f, 100.0f, "%.1f", ImGuiSliderFlags_None)) { + graph->y_axis_max_time_ms = max_time_slider; + } + + if (igInputFloat("Target time reference (ms)", &target_time_input, 0.0f, 0.0f, "%.3f", ImGuiInputTextFlags_EnterReturnsTrue)) { + if (target_time_input >= 0.1f && target_time_input <= 100.0f) { + graph->target_time_ms = target_time_input; + } else { + target_time_input = graph->target_time_ms; + } + } + + igCheckbox("Show reference line labels", &show_labels); + igCheckbox("Show target reference line", &show_target_line); + igCheckbox("Show average reference line", &show_avg_line); + + if (igButton("Focus on average", (ImVec2){0, 0})) { + // Convert +/- 10 fps around average to milliseconds + float avg_fps = 1000.0f / history->avg_time_ms; + graph->y_axis_min_time_ms = 1000.0f / (avg_fps + 10.0f); + graph->y_axis_max_time_ms = 1000.0f / fmaxf(avg_fps - 10.0f, 1.0f); + } + + igSameLine(0, -1); + + if (igButton("Focus on target", (ImVec2){0, 0})) { + // Convert +/- 10 fps around target to milliseconds + float target_fps = 1000.0f / graph->target_time_ms; + graph->y_axis_min_time_ms = 1000.0f / (target_fps + 10.0f); + graph->y_axis_max_time_ms = 1000.0f / fmaxf(target_fps - 10.0f, 1.0f); + } + + igPopItemWidth(); + igEndMenu(); + } + igEndMenuBar(); + } + + igGetContentRegionAvail(&window_size); + + igPushStyleColor_Vec4(ImGuiCol_Text, (ImVec4){1, 1, 0, 1}); + igText("Now %.3f ms", current_value); + igPopStyleColor(1); + igSameLine(0, -1); + igPushStyleColor_Vec4(ImGuiCol_Text, (ImVec4){1, 0, 0, 1}); + igText("Target %.3f ms", graph->target_time_ms); + igPopStyleColor(1); + igPushStyleColor_Vec4(ImGuiCol_Text, (ImVec4){0, 1, 0, 1}); + igText("Avg %.3f ms", history->avg_time_ms); + igPopStyleColor(1); + igSameLine(0, -1); + igText(" Min %.3f ms Max %.3f ms", history->min_time_ms, history->max_time_ms); + + // Setup plot area using actual window size, with extra space at top for "ms" label + ImVec2 plot_pos; + igGetCursorScreenPos(&plot_pos); + plot_pos.y += 15; // Add space at top for "ms" label + ImVec2 plot_size = {window_size.x - 50, window_size.y - 65}; // Adjusted for extra top space + + // Plot frame times in ms + ImVec2 plot_pos_offset = {plot_pos.x + 50, plot_pos.y}; + igSetCursorScreenPos(plot_pos_offset); + + igPlotLines_FloatPtr("##framegraph", + history->time_values_ms, + history->size, + history->current_index, + "", + graph->y_axis_min_time_ms, + graph->y_axis_max_time_ms, + plot_size, + sizeof(float)); + + // Draw Y axis (ms) + ImDrawList* draw_list = igGetWindowDrawList(); + char y_label[32]; + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, plot_pos.y}, + (ImVec2){plot_pos.x + 50, plot_pos.y + plot_size.y}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), 1.0f); + + // Draw "ms" label at top of y-axis + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 5, plot_pos.y - 15}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), "ms", NULL); + + // Scale number of reference points based on plot height + int num_reference_points = (int)(plot_size.y / 25); // One point per ~40 pixels + if (num_reference_points < 4) num_reference_points = 4; + + float time_min = graph->y_axis_min_time_ms; + float time_max = graph->y_axis_max_time_ms; + float time_step = (time_max - time_min) / (num_reference_points + 1); + + // Draw min time value at top of y-axis and reference line + snprintf(y_label, sizeof(y_label), "%.2f", time_min); + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 5, plot_pos.y + plot_size.y - 10}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), y_label, NULL); + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, plot_pos.y + plot_size.y}, + (ImVec2){plot_pos.x + plot_size.x + 50, plot_pos.y + plot_size.y}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,0.3f}), 1.0f); + + // Draw reference points and lines on side of y-axis + for (int i = 1; i <= num_reference_points; i++) { + float value = time_max - (time_step * i); + float normalized_pos = (time_max - value) / (time_max - time_min); + float y_pos = plot_pos.y + (plot_size.y * normalized_pos); + snprintf(y_label, sizeof(y_label), "%.2f", value); + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 5, y_pos - 5}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), y_label, NULL); + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, y_pos}, + (ImVec2){plot_pos.x + plot_size.x + 50, y_pos}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,0.2f}), 1.0f); + } + + // Draw max time value at bottom of y-axis and reference line + snprintf(y_label, sizeof(y_label), "%.2f", time_max); + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 5, plot_pos.y}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), y_label, NULL); + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, plot_pos.y}, + (ImVec2){plot_pos.x + plot_size.x + 50, plot_pos.y}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,0.3f}), 1.0f); + + // Draw target frame time reference line if within plot area + if (show_target_line && graph->target_time_ms >= time_min && graph->target_time_ms <= time_max) { + float normalized_target = (time_max - graph->target_time_ms) / (time_max - time_min); + float y_pos_target = plot_pos.y + (plot_size.y * normalized_target); + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, y_pos_target}, + (ImVec2){plot_pos.x + plot_size.x + 50, y_pos_target}, + igColorConvertFloat4ToU32((ImVec4){1,0,0,1.0f}), 1.0f); + if (show_labels) { + snprintf(y_label, sizeof(y_label), "%.3f", graph->target_time_ms); + ImDrawList_AddText_Vec2(draw_list, + (ImVec2){plot_pos.x + 50 + plot_size.x/2 - 10, y_pos_target + 5}, + igColorConvertFloat4ToU32((ImVec4){1,0,0,1}), y_label, NULL); + } + } + + // Draw reference line for current average if within plot area + if (show_avg_line && history->avg_time_ms >= time_min && history->avg_time_ms <= time_max) { + float normalized_avg = (time_max - history->avg_time_ms) / (time_max - time_min); + float y_pos_avg = plot_pos.y + (plot_size.y * normalized_avg); + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, y_pos_avg}, + (ImVec2){plot_pos.x + plot_size.x + 50, y_pos_avg}, + igColorConvertFloat4ToU32((ImVec4){0,1,0,1.0f}), 1.0f); + if (show_labels) { + snprintf(y_label, sizeof(y_label), "%.3f", history->avg_time_ms); + ImDrawList_AddText_Vec2(draw_list, + (ImVec2){plot_pos.x + 50 + plot_size.x/2 - 10, y_pos_avg + 5}, + igColorConvertFloat4ToU32((ImVec4){0,1,0,1}), y_label, NULL); + } + } + + // Draw X axis (time in frames) + ImDrawList_AddLine(draw_list, + (ImVec2){plot_pos.x + 50, plot_pos.y + plot_size.y}, + (ImVec2){plot_pos.x + plot_size.x + 50, plot_pos.y + plot_size.y}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), 1.0f); + + // Draw "frames" label centered on x-axis + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 50 + (plot_size.x / 2) - 20, plot_pos.y + plot_size.y + 5}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), "frames ago", NULL); + + char x_label[32]; + snprintf(x_label, sizeof(x_label), "%d", history->size); + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + 50, plot_pos.y + plot_size.y + 5}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), x_label, NULL); + ImDrawList_AddText_Vec2(draw_list, (ImVec2){plot_pos.x + plot_size.x + 50, plot_pos.y + plot_size.y + 5}, + igColorConvertFloat4ToU32((ImVec4){1,1,1,1}), "0", NULL); + + igEnd(); +} + +static void _imgui_debug_frame_perf_graph_component_frame_update(ImGuiContext *ctx) +{ + ImGuiIO *io; + + log_assert(ctx); + + igSetCurrentContext(ctx); + io = igGetIO(); + + imgui_debug_time_history_update(&_imgui_debug_frame_perf_graph_history, 1000.0f / io->Framerate); + + _imgui_debug_frame_perf_graph_draw(&_imgui_debug_frame_perf_graph, &_imgui_debug_frame_perf_graph_history); +} + +void imgui_debug_frame_perf_graph_init( + float target_fps, + imgui_bt_component_t *component) +{ + log_assert(target_fps > 0.0f); + log_assert(component); + + imgui_debug_time_history_init(ceilf(10 * target_fps), &_imgui_debug_frame_perf_graph_history); + + _imgui_debug_frame_perf_graph.target_time_ms = 1000.0f / target_fps; + _imgui_debug_frame_perf_graph.y_axis_min_time_ms = 1000.0f / fmaxf(0.0f, target_fps - 20.0f); + _imgui_debug_frame_perf_graph.y_axis_max_time_ms = 1000.0f / fminf(target_fps + 20.0f, 1000.0f); + + component->frame_update = _imgui_debug_frame_perf_graph_component_frame_update; +} \ No newline at end of file diff --git a/src/main/imgui-debug/frame-perf-graph.h b/src/main/imgui-debug/frame-perf-graph.h new file mode 100644 index 0000000..e2040a0 --- /dev/null +++ b/src/main/imgui-debug/frame-perf-graph.h @@ -0,0 +1,10 @@ +#ifndef IMGUI_DEBUG_FRAME_PERF_GRAPH_H +#define IMGUI_DEBUG_FRAME_PERF_GRAPH_H + +#include "imgui-bt/component.h" + +void imgui_debug_frame_perf_graph_init( + float target_fps, + imgui_bt_component_t *component); + +#endif \ No newline at end of file diff --git a/src/main/imgui-debug/time-history.c b/src/main/imgui-debug/time-history.c new file mode 100644 index 0000000..000320f --- /dev/null +++ b/src/main/imgui-debug/time-history.c @@ -0,0 +1,63 @@ +#include +#include + +#include "time-history.h" + +#include "util/log.h" +#include "util/mem.h" + +void imgui_debug_time_history_init(uint32_t size, imgui_debug_time_history_t *history) +{ + log_assert(size > 0); + log_assert(history); + + memset(history, 0, sizeof(imgui_debug_time_history_t)); + + history->size = size; + history->time_values_ms = (float *) xmalloc(size * sizeof(float)); +} + +void imgui_debug_time_history_update(imgui_debug_time_history_t *history, float time_ms) +{ + log_assert(history); + + history->time_values_ms[history->current_index] = time_ms; + history->current_index = (history->current_index + 1) % history->size; + + history->min_time_ms = history->time_values_ms[0]; + history->max_time_ms = history->time_values_ms[0]; + history->avg_time_ms = 0; + + for (uint32_t i = 0; i < history->size; i++) { + if (history->time_values_ms[i] < history->min_time_ms) { + history->min_time_ms = history->time_values_ms[i]; + } + + if (history->time_values_ms[i] > history->max_time_ms) { + history->max_time_ms = history->time_values_ms[i]; + } + + history->avg_time_ms += history->time_values_ms[i]; + } + + history->avg_time_ms /= history->size; +} + +float imgui_debug_time_history_recent_value_get(const imgui_debug_time_history_t *history) +{ + log_assert(history); + + if (history->current_index == 0) { + return history->time_values_ms[history->size - 1]; + } else { + return history->time_values_ms[history->current_index - 1]; + } +} + +void imgui_debug_time_history_free(imgui_debug_time_history_t *history) +{ + log_assert(history); + log_assert(history->time_values_ms); + + free(history->time_values_ms); +} \ No newline at end of file diff --git a/src/main/imgui-debug/time-history.h b/src/main/imgui-debug/time-history.h new file mode 100644 index 0000000..0a56f51 --- /dev/null +++ b/src/main/imgui-debug/time-history.h @@ -0,0 +1,23 @@ +#ifndef IMGUI_DEBUG_TIME_HISTORY_H +#define IMGUI_DEBUG_TIME_HISTORY_H + +#include + +typedef struct imgui_debug_time_history { + uint32_t size; + float *time_values_ms; + uint32_t current_index; + float min_time_ms; + float max_time_ms; + float avg_time_ms; +} imgui_debug_time_history_t; + +void imgui_debug_time_history_init(uint32_t size, imgui_debug_time_history_t *history); + +void imgui_debug_time_history_update(imgui_debug_time_history_t *history, float time_ms); + +float imgui_debug_time_history_recent_value_get(const imgui_debug_time_history_t *history); + +void imgui_debug_time_history_free(imgui_debug_time_history_t *history); + +#endif \ No newline at end of file diff --git a/src/main/util/Module.mk b/src/main/util/Module.mk index ab8d495..1a48cd3 100644 --- a/src/main/util/Module.mk +++ b/src/main/util/Module.mk @@ -20,5 +20,6 @@ src_util := \ str.c \ thread.c \ time.c \ + winerr.c \ winres.c \ diff --git a/src/main/util/proc.c b/src/main/util/proc.c index 8473113..47c5d3a 100644 --- a/src/main/util/proc.c +++ b/src/main/util/proc.c @@ -1,54 +1,25 @@ #define LOG_MODULE "util-proc" #include -#include - -#include -#include +#include +#include +#include +#include "util/defs.h" #include "util/log.h" +#include "util/mem.h" +#include "util/str.h" +#include "util/winerr.h" -bool proc_is_running_as_admin_user() -{ - SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY; - PSID sid; - BOOL res; - BOOL is_admin; +#include "proc.h" - res = AllocateAndInitializeSid( - &authority, - 2, - SECURITY_BUILTIN_DOMAIN_RID, - DOMAIN_ALIAS_RID_ADMINS, - 0, - 0, - 0, - 0, - 0, - 0, - &sid); - - if (!res) { - log_warning( - "Failed to allocate memory for is admin check: %lX", - GetLastError()); - return false; - } - - is_admin = false; - - res = CheckTokenMembership(NULL, sid, &is_admin); - - if (!res) { - log_warning( - "Failed to check admin group membership: %lX", GetLastError()); - return false; - } - - FreeSid(sid); - - return is_admin; -} +typedef NTSTATUS (NTAPI *PNtQueryInformationThread)( + HANDLE ThreadHandle, + THREADINFOCLASS ThreadInformationClass, + PVOID ThreadInformation, + ULONG ThreadInformationLength, + PULONG ReturnLength +); void proc_terminate_current_process(uint32_t exit_code) { @@ -58,4 +29,196 @@ void proc_terminate_current_process(uint32_t exit_code) SYNCHRONIZE | PROCESS_TERMINATE, TRUE, GetCurrentProcessId()); TerminateProcess(hnd, exit_code); +} + +void* proc_thread_get_proc_address(int thread_id) +{ + HANDLE thread; + char* err_str; + HMODULE nt_dll; + PNtQueryInformationThread ntQueryInformationThread; + NTSTATUS status; + PVOID thread_start_address; + ULONG return_len; + + thread = proc_thread_get_handle(thread_id); + + if (thread == NULL) { + err_str = util_winerr_format_last_error_code(); + log_fatal("Failed to open thread with id %d: %s", thread_id, err_str); + } + + nt_dll = LoadLibrary("ntdll.dll"); + ntQueryInformationThread = (PNtQueryInformationThread) GetProcAddress(nt_dll, "NtQueryInformationThread"); + + status = ntQueryInformationThread(thread, ThreadQuerySetWin32StartAddress, &thread_start_address, sizeof(thread_start_address), &return_len); + + CloseHandle(thread); + FreeLibrary(nt_dll); + + if (status != STATUS_SUCCESS) { + log_fatal("Failed to get start address for thread %d: 0x%lx\n", thread_id, status); + } + + return thread_start_address; +} + +HMODULE proc_thread_proc_get_origin_module(void* proc_addr) +{ + HMODULE module; + + log_assert(proc_addr); + + if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCTSTR) proc_addr, &module)) { + return NULL; + } else { + return module; + } +} + +bool proc_thread_proc_get_origin_module_path(void* proc_addr, char* buffer, size_t len) +{ + HMODULE module; + + module = proc_thread_proc_get_origin_module(proc_addr); + + if (module != NULL) { + if (GetModuleFileNameA(module, buffer, len) == 0) { + return false; + } else { + return true; + } + } else { + return false; + } +} + +bool proc_thread_proc_get_origin_module_name(void* proc_addr, char* buffer, size_t len) +{ + HMODULE module; + char path_buffer[MAX_PATH]; + const char* filename; + + module = proc_thread_proc_get_origin_module(proc_addr); + + if (module != NULL) { + if (GetModuleFileNameA(module, path_buffer, sizeof(path_buffer)) == 0) { + return false; + } else { + filename = strrchr(path_buffer, '\\'); + + if (filename == NULL) { + // no backslashes found, use the entire path + filename = path_buffer; + } else { + // skip the backslash + filename++; + } + + str_cpy(buffer, len, filename); + + return true; + } + } else { + return false; + } +} + +size_t proc_thread_scan_threads_current_process(struct proc_thread_info** info) +{ + DWORD pid; + HANDLE snapshot; + char* err_str; + THREADENTRY32 thread_entry; + size_t idx; + HANDLE thread; + + log_assert(info); + + pid = GetCurrentProcessId(); + + // Create a snapshot of the running threads in the target process. + snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pid); + + if (snapshot == INVALID_HANDLE_VALUE) { + err_str = util_winerr_format_last_error_code(); + log_fatal("Failed to create snapshot of threads: %s", err_str); + } + + thread_entry.dwSize = sizeof(THREADENTRY32); + + idx = 0; + *info = NULL; + + // Count entries for allocation of return value + if (Thread32First(snapshot, &thread_entry)) { + do { + if (thread_entry.th32OwnerProcessID == pid) { + *info = xrealloc(*info, (idx + 1) * sizeof(struct proc_thread_info)); + + thread = proc_thread_get_handle(thread_entry.th32ThreadID); + + (*info)[idx].id = thread_entry.th32ThreadID; + (*info)[idx].proc = proc_thread_get_proc_address(thread_entry.th32ThreadID); + (*info)[idx].priority = GetThreadPriority(thread); + (*info)[idx].origin_module = proc_thread_proc_get_origin_module((*info)[idx].proc); + + CloseHandle(thread); + + idx++; + } + } while (Thread32Next(snapshot, &thread_entry)); + } + + CloseHandle(snapshot); + + return idx; +} + +HANDLE proc_thread_get_handle(int thread_id) +{ + HANDLE handle; + + handle = OpenThread(THREAD_ALL_ACCESS, FALSE, thread_id); + + return handle; +} + +bool proc_thread_set_priority(int thread_id, int priority) +{ + HANDLE thread; + BOOL res; + + thread = proc_thread_get_handle(thread_id); + + if (thread == NULL) { + return false; + } + + res = SetThreadPriority(thread, priority); + + CloseHandle(thread); + + return res; +} + +bool proc_thread_set_affinity(int thread_id, uint32_t cpu_mask) +{ + HANDLE thread; + DWORD_PTR affinity_mask; + DWORD_PTR prev_affinity_mask; + + thread = proc_thread_get_handle(thread_id); + + if (thread == NULL) { + return false; + } + + affinity_mask = cpu_mask; + prev_affinity_mask = SetThreadAffinityMask(thread, affinity_mask); + + CloseHandle(thread); + + return prev_affinity_mask != 0; } \ No newline at end of file diff --git a/src/main/util/proc.h b/src/main/util/proc.h index be47a40..246ee75 100644 --- a/src/main/util/proc.h +++ b/src/main/util/proc.h @@ -1,8 +1,37 @@ #pragma once +#include + #include #include +#include -bool proc_is_running_as_admin_user(); +#define PROC_THREAD_CPU_AFFINITY_CORE(c) (1 << c) -void proc_terminate_current_process(uint32_t exit_code); \ No newline at end of file +struct proc_thread_info { + int id; + void* proc; + // According to + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadpriority#return-value + int priority; + HMODULE origin_module; +}; + +void proc_terminate_current_process(uint32_t exit_code); + +void* proc_thread_get_proc_address(int thread_id); + +HMODULE proc_thread_proc_get_origin_module(void* proc_addr); + +bool proc_thread_proc_get_origin_module_path(void* proc_addr, char* buffer, size_t len); + +bool proc_thread_proc_get_origin_module_name(void* proc_addr, char* buffer, size_t len); + +size_t proc_thread_scan_threads_current_process(struct proc_thread_info** info); + +HANDLE proc_thread_get_handle(int thread_id); + +bool proc_thread_set_priority(int thread_id, int priority); + +// cpu starts with 0, specify multiple to set affinity to these cores +bool proc_thread_set_affinity(int thread_id, uint32_t cpu_mask); \ No newline at end of file