From e15c6890617bed3fe68eaaf8826538aceab9eda5 Mon Sep 17 00:00:00 2001 From: "[ ]" <[ ]> Date: Wed, 19 Nov 2025 08:13:37 +0900 Subject: [PATCH] feat: Resolve low framerate during song select for IIDX32+ > caused by bad code around thumbnail fetching logic including file checks in every draw call, see #4 > added `hooks::wmisc` for linux specific minor performance fixes and similar --- CMakeLists.txt | 1 + games/iidx/iidx.cpp | 4 ++- hooks/develhook.cpp | 29 +++++++++++++++++- hooks/develhook.h | 1 + hooks/sndbhook.cpp | 4 +-- hooks/sndbhook.h | 2 +- hooks/wmischook.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++ hooks/wmischook.h | 7 +++++ 8 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 hooks/wmischook.cpp create mode 100644 hooks/wmischook.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d0d8f2..eea7b3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -488,6 +488,7 @@ set(SOURCE_FILES ${SOURCE_FILES} hooks/audio/implementations/pipewire.cpp hooks/develhook.cpp hooks/sndbhook.cpp + hooks/wmischook.cpp hooks/avshook.cpp hooks/cfgmgr32hook.cpp hooks/debughook.cpp diff --git a/games/iidx/iidx.cpp b/games/iidx/iidx.cpp index 9513d03..da27792 100644 --- a/games/iidx/iidx.cpp +++ b/games/iidx/iidx.cpp @@ -19,6 +19,7 @@ #include "hooks/setupapihook.h" #include "hooks/sleephook.h" #include "hooks/sndbhook.h" +#include "hooks/wmischook.h" #include "launcher/options.h" #include "touch/touch.h" #include "misc/wintouchemu.h" @@ -408,7 +409,8 @@ namespace games::iidx { cfgmgr32hook_init(avs::game::DLL_INSTANCE); // wine fixes - hooks::soundbank::init(avs::game::DLL_INSTANCE, avs::game::EXT); + hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, avs::game::MODEL, avs::game::EXT); + hooks::soundbank::init(avs::game::DLL_INSTANCE, avs::game::MODEL, avs::game::EXT); // report common errors on iidx31 and above if (avs::game::is_ext(2023091500, MAXINT) && GRAPHICS_9_ON_12_STATE == DX9ON12_FORCE_ON) { diff --git a/hooks/develhook.cpp b/hooks/develhook.cpp index fbf5009..776de86 100644 --- a/hooks/develhook.cpp +++ b/hooks/develhook.cpp @@ -1,11 +1,33 @@ #include "develhook.h" #include "util/logging.h" #include "util/detour.h" +#include "util/libutils.h" #include "avs/core.h" +#include "avs/game.h" +#include "hooks/wmischook.h" +#include "external/stackwalker/stackwalker.h" #include #include #include +namespace hooks::devel::thumbnail +{ +typedef int (*BmswSymlink_t)(const char *srcwpath, const char *dstwpath, int canonic); +static BmswSymlink_t BmswSymlink; + +void run() +{ + HMODULE bmsw_ = nullptr; + if ((bmsw_ = libutils::try_library(MODULE_PATH / "bmsound-wine.dll"))) + { + BmswSymlink = (BmswSymlink_t) GetProcAddress(bmsw_, "BmswSymlink"); + } + + log_warning("hooks::devel::thumbnail", "Forcing thumbnail patch.."); + hooks::wmisc::apply_performance_hacks(avs::game::DLL_INSTANCE, "LDJ", "20250825"); +} + +} namespace hooks::devel::avs_fs { @@ -49,7 +71,9 @@ void run() namespace hooks::devel { void (*routine_cb_[devel_routine_last])() ={ - [avs_fs_detour] = avs_fs::run + [avs_fs_detour] = avs_fs::run, + [sndb_test] = nullptr, + [thum_test] = thumbnail::run }; static constexpr unsigned int by_str(const char *str, int h = 0) @@ -85,6 +109,9 @@ static devel_routine_t routines() case by_str("sndb_test"): routines_ |= 1 << sndb_test; break; + case by_str("thum_test"): + routines_ |= 1 << thum_test; + break; default: break; } diff --git a/hooks/develhook.h b/hooks/develhook.h index 89eb741..133ea94 100644 --- a/hooks/develhook.h +++ b/hooks/develhook.h @@ -9,6 +9,7 @@ enum devel_routine : uint32_t { avs_fs_detour = 0, sndb_test, + thum_test, devel_routine_last }; typedef uint32_t devel_routine_t; diff --git a/hooks/sndbhook.cpp b/hooks/sndbhook.cpp index 13aa6e4..19fb232 100644 --- a/hooks/sndbhook.cpp +++ b/hooks/sndbhook.cpp @@ -494,7 +494,7 @@ private: static snd_bank *cache_; static size_t cachesz_; static avcodec::pcm_resampler_t resampler_; - friend void hooks::soundbank::init(HINSTANCE hmodule, const char *ext); + friend void hooks::soundbank::init(HINSTANCE hmodule, const char *model, const char *ext); uint8_t uid_; uint32_t mnt_; @@ -872,7 +872,7 @@ void run_tests() snd_bank::flush_cache(); mf_broken::deinit(); } -void init(HINSTANCE hmodule, const char *ext) +void init(HINSTANCE hmodule, const char *model, const char *ext) { if (false && IsDebuggerPresent()) { diff --git a/hooks/sndbhook.h b/hooks/sndbhook.h index 9657ed8..c4bf027 100644 --- a/hooks/sndbhook.h +++ b/hooks/sndbhook.h @@ -3,6 +3,6 @@ namespace hooks::soundbank { -void init(HINSTANCE hmodule, const char *ext); +void init(HINSTANCE hmodule, const char *model, const char *ext); void deinit(HINSTANCE hmodule); } diff --git a/hooks/wmischook.cpp b/hooks/wmischook.cpp new file mode 100644 index 0000000..c48bf19 --- /dev/null +++ b/hooks/wmischook.cpp @@ -0,0 +1,72 @@ +#include "wmischook.h" +#include "util/logging.h" +#include "util/detour.h" +#include "util/sigscan.h" + + +namespace hooks::wmisc::thumbnail +{ +typedef bool (*ThumExists_t)(void *titleUTF_getter, int32_t id, char flag); +static ThumExists_t ThumExists; + +bool on_thum_exists_(void *titleUTF_getter, int32_t id, char flag) +{ + static std::unordered_map thumids; + auto it = thumids.find(id); + if (it != thumids.end()) + { + return it->second; + } + else + { + log_misc("hooks::wmisc::thumbnail", "Caching state for [{}]", id); + it = thumids.insert({id, ThumExists(titleUTF_getter, id, flag)}).first; + } + + return it->second; +} + +void run(HINSTANCE hmodule) +{ + // Reverse lookup function head (PUSH RDI) for ThumExists() specific signature, quietly fail if invalid + intptr_t beg, match, TX_ThumExists; + TX_ThumExists = beg = match = find_pattern_from(hmodule, "83f801750c4084ff750732c0", "XXXXXXXXXXXX", 0, 0, 0); + while (beg > sizeof(intptr_t) && match >= TX_ThumExists) + { + beg--; + match = find_pattern_from(hmodule, "4057", "XX", 0, 0, beg - reinterpret_cast(hmodule)); + } + TX_ThumExists = match; + log_info("hooks::wmisc::thumbnail", "Hooking ThumExists({})", reinterpret_cast(TX_ThumExists)); + detour::trampoline_try(reinterpret_cast(TX_ThumExists), reinterpret_cast(on_thum_exists_), reinterpret_cast(&ThumExists)); +} +} + +namespace hooks::wmisc +{ +static constexpr unsigned int by_model(const char *model, int h = 0) +{ + return !model[h] ? 5381 : (by_model(model, h + 1) * 33) ^ model[h]; +} +static constexpr unsigned int by_ext(const char *ext, int h = 0) +{ + return !ext[h] ? 5381 : (by_ext(ext, h + 1) * 33) ^ ext[h]; +} + + +void apply_performance_hacks(HINSTANCE hmodule, const char *model, const char *ext) +{ + log_info("hooks::wmisc", "Enabling performance patches for {}-{}", model, ext); + switch (by_model(model)) + { + case by_model("LDJ"): + thumbnail::run(hmodule); + break; + default: + break; + } + +} + + +} diff --git a/hooks/wmischook.h b/hooks/wmischook.h new file mode 100644 index 0000000..8bbf987 --- /dev/null +++ b/hooks/wmischook.h @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace hooks::wmisc +{ +void apply_performance_hacks(HINSTANCE hmodule, const char *model, const char *ext); +}