1
0
mirror of synced 2025-02-25 22:08:34 +01:00

impr: Don't wake up frame rate limiter thread more often than necessary

This commit is contained in:
WerWolv 2025-02-23 20:25:29 +01:00
parent 4c0e8bc1d6
commit 7879f8b6a4
3 changed files with 54 additions and 25 deletions

View File

@ -53,6 +53,9 @@ namespace hex {
void drawImGui();
void drawWithShader();
void unlockFrameRate();
void forceNewFrame();
GLFWwindow *m_window = nullptr;
std::string m_windowTitle, m_windowTitleFull;
@ -64,17 +67,22 @@ namespace hex {
std::list<std::string> m_popupsToOpen;
std::set<int> m_pressedKeys;
std::atomic<bool> m_unlockFrameRate = true;
ImGuiExt::ImHexCustomData m_imguiCustomData;
u32 m_searchBarPosition = 0;
bool m_emergencyPopupOpen = false;
std::jthread m_frameRateThread;
std::chrono::duration<double, std::nano> m_remainingUnlockedTime;
std::mutex m_sleepMutex;
std::atomic<bool> m_sleepFlag;
std::condition_variable m_sleepCondVar;
std::mutex m_sleepMutex;
std::mutex m_wakeupMutex;
std::atomic<bool> m_wakeupFlag;
std::condition_variable m_wakeupCondVar;
gl::Shader m_postProcessingShader;
};

View File

@ -618,7 +618,7 @@ namespace hex {
glfwSetFramebufferSizeCallback(m_window, [](GLFWwindow* window, int width, int height) {
auto *win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->m_unlockFrameRate = true;
win->unlockFrameRate();
glViewport(0, 0, width, height);
ImHexApi::System::impl::setMainWindowSize(width, height);

View File

@ -311,7 +311,7 @@ namespace hex {
// Unlock frame rate if any mouse button is being held down to allow drag scrolling to be smooth
if (ImGui::IsAnyMouseDown())
m_unlockFrameRate = true;
this->unlockFrameRate();
// Unlock frame rate if any modifier key is held down since they don't generate key repeat events
if (
@ -320,12 +320,12 @@ namespace hex {
ImGui::IsKeyPressed(ImGuiKey_LeftSuper) || ImGui::IsKeyPressed(ImGuiKey_RightSuper) ||
ImGui::IsKeyPressed(ImGuiKey_LeftAlt) || ImGui::IsKeyPressed(ImGuiKey_RightAlt)
) {
m_unlockFrameRate = true;
this->unlockFrameRate();
}
// Unlock frame rate if there's more than one viewport since these don't call the glfw callbacks registered here
if (ImGui::GetPlatformIO().Viewports.size() > 1)
m_unlockFrameRate = true;
this->unlockFrameRate();
}
// Hide the window as soon as the render loop exits to make the window
@ -929,6 +929,23 @@ namespace hex {
#endif
}
void Window::unlockFrameRate() {
{
std::scoped_lock lock(m_wakeupMutex);
m_remainingUnlockedTime = std::chrono::seconds(2);
}
this->forceNewFrame();
}
void Window::forceNewFrame() {
std::scoped_lock lock(m_wakeupMutex);
m_wakeupFlag = true;
m_wakeupCondVar.notify_all();
}
void Window::initGLFW() {
auto initialWindowProperties = ImHexApi::System::getInitialWindowProperties();
glfwSetErrorCallback([](int error, const char *desc) {
@ -1029,7 +1046,7 @@ namespace hex {
if (win == nullptr)
return;
win->m_unlockFrameRate = true;
win->unlockFrameRate();
};
static const auto isMainWindow = [](GLFWwindow *window) {
@ -1165,7 +1182,7 @@ namespace hex {
Duration passedTime = {};
std::chrono::steady_clock::time_point startTime = {}, endTime = {};
Duration requestedFrameTime = {}, remainingUnlockedTime = {};
Duration requestedFrameTime = {};
float targetFps = 0;
const auto nativeFps = []() -> float {
@ -1184,32 +1201,36 @@ namespace hex {
targetFps = ImHexApi::System::getTargetFPS();
if (m_unlockFrameRate.exchange(false)) {
remainingUnlockedTime = std::chrono::seconds(2);
}
// If the target frame rate is below 15, use the current monitor's refresh rate
if (targetFps < 15) {
targetFps = nativeFps;
}
passedTime += iterationTime;
if (remainingUnlockedTime > std::chrono::nanoseconds(0)) {
remainingUnlockedTime -= iterationTime;
} else {
targetFps = 5;
}
requestedFrameTime = (Duration(1.0E9) / targetFps) / 1.3;
if (passedTime >= requestedFrameTime) {
{
std::scoped_lock lock(m_sleepMutex);
m_sleepFlag = true;
m_sleepCondVar.notify_all();
passedTime = {};
if (m_remainingUnlockedTime > std::chrono::nanoseconds(0)) {
m_remainingUnlockedTime -= iterationTime;
} else {
targetFps = 0.01;
}
requestedFrameTime = (Duration(1.0E9) / targetFps) / 1.3;
if (passedTime >= requestedFrameTime) {
m_sleepFlag = true;
m_sleepCondVar.notify_all();
passedTime = {};
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
{
std::unique_lock lock(m_wakeupMutex);
m_wakeupCondVar.wait_for(lock, requestedFrameTime, [&] {
return m_wakeupFlag || stopToken.stop_requested();
});
}
endTime = std::chrono::steady_clock::now();
}