1
0
mirror of synced 2025-01-18 00:56:49 +01:00

impr: Implement rendering power saving using hashes

This commit is contained in:
WerWolv 2023-12-27 13:54:00 +01:00
parent 1cf692cecf
commit e414c1cf1e
2 changed files with 56 additions and 82 deletions

View File

@ -38,8 +38,6 @@ namespace hex {
void frame(); void frame();
void frameEnd(); void frameEnd();
void processEvent() { m_hadEvent = true; }
void initGLFW(); void initGLFW();
void initImGui(); void initImGui();
void exitGLFW(); void exitGLFW();
@ -60,11 +58,7 @@ namespace hex {
std::list<std::string> m_popupsToOpen; std::list<std::string> m_popupsToOpen;
std::vector<int> m_pressedKeys; std::vector<int> m_pressedKeys;
bool m_buttonDown = false; bool m_unlockFrameRate = false;
bool m_hadEvent = false;
bool m_frameRateTemporarilyUnlocked = false;
double m_frameRateUnlockTime = 0;
ImGuiExt::ImHexCustomData m_imguiCustomData; ImGuiExt::ImHexCustomData m_imguiCustomData;
}; };

View File

@ -174,38 +174,30 @@ namespace hex {
while (!glfwWindowShouldClose(m_window)) { while (!glfwWindowShouldClose(m_window)) {
m_lastStartFrameTime = glfwGetTime(); m_lastStartFrameTime = glfwGetTime();
bool shouldLongSleep = !m_unlockFrameRate;
static i32 lockTimeout = 0;
if (!shouldLongSleep) {
lockTimeout = 2;
} else if (lockTimeout > 0) {
lockTimeout -= 1;
}
if (shouldLongSleep && lockTimeout > 0)
shouldLongSleep = false;
m_unlockFrameRate = false;
if (!glfwGetWindowAttrib(m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(m_window, GLFW_ICONIFIED)) { if (!glfwGetWindowAttrib(m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(m_window, GLFW_ICONIFIED)) {
// If the application is minimized or not visible, don't render anything // If the application is minimized or not visible, don't render anything
glfwWaitEvents(); glfwWaitEvents();
} else { } else {
// If no events have been received in a while, lower the frame rate // If no events have been received in a while, lower the frame rate
{ {
// If the mouse is down, the mouse is moving or a popup is open, we don't want to lower the frame rate
bool frameRateUnlocked =
ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) ||
TaskManager::getRunningTaskCount() > 0 ||
m_buttonDown ||
m_hadEvent ||
!m_pressedKeys.empty() ||
frameCount < 100;
m_hadEvent = false;
// Calculate the time until the next frame // Calculate the time until the next frame
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - m_lastStartFrameTime)); const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - m_lastStartFrameTime));
// If the frame rate has been unlocked for 5 seconds, lock it again if (shouldLongSleep)
if ((m_lastStartFrameTime - m_frameRateUnlockTime) > 5 && m_frameRateTemporarilyUnlocked && !frameRateUnlocked) {
m_frameRateTemporarilyUnlocked = false;
}
// If the frame rate is locked, wait for events with a timeout
if (frameRateUnlocked && !m_frameRateTemporarilyUnlocked) {
m_frameRateTemporarilyUnlocked = true;
m_frameRateUnlockTime = m_lastStartFrameTime;
}
if (!m_frameRateTemporarilyUnlocked)
glfwWaitEventsTimeout(timeout); glfwWaitEventsTimeout(timeout);
} }
} }
@ -223,7 +215,7 @@ namespace hex {
} else if (targetFPS > 200) { } else if (targetFPS > 200) {
glfwSwapInterval(0); glfwSwapInterval(0);
} else { } else {
if (m_frameRateTemporarilyUnlocked) { if (!shouldLongSleep) {
glfwSwapInterval(0); glfwSwapInterval(0);
const auto frameTime = glfwGetTime() - m_lastStartFrameTime; const auto frameTime = glfwGetTime() - m_lastStartFrameTime;
const auto targetFrameTime = 1.0 / targetFPS; const auto targetFrameTime = 1.0 / targetFPS;
@ -889,22 +881,49 @@ namespace hex {
this->endNativeWindowFrame(); this->endNativeWindowFrame();
// Render UI // Finalize ImGui frame
ImGui::Render(); ImGui::Render();
int displayWidth, displayHeight; // Hash the draw data to determine if anything changed on the screen
glfwGetFramebufferSize(m_window, &displayWidth, &displayHeight); // If not, there's no point in sending the draw data off to the GPU and swapping buffers
glViewport(0, 0, displayWidth, displayHeight); bool shouldRender = false;
glClearColor(0.00F, 0.00F, 0.00F, 0.00F); {
glClear(GL_COLOR_BUFFER_BIT); u32 drawDataHash = 0;
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); static u32 previousDrawDataHash = 0;
GLFWwindow *backup_current_context = glfwGetCurrentContext(); for (const auto viewPort : ImGui::GetPlatformIO().Viewports) {
auto drawData = viewPort->DrawData;
for (int n = 0; n < drawData->CmdListsCount; n++) {
const ImDrawList *cmd_list = drawData->CmdLists[n];
drawDataHash = ImHashData(cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert), drawDataHash);
}
for (int n = 0; n < drawData->CmdListsCount; n++) {
const ImDrawList *cmd_list = drawData->CmdLists[n];
drawDataHash = ImHashData(cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx), drawDataHash);
}
}
shouldRender = drawDataHash != previousDrawDataHash;
previousDrawDataHash = drawDataHash;
}
if (shouldRender) {
int displayWidth, displayHeight;
glfwGetFramebufferSize(m_window, &displayWidth, &displayHeight);
glViewport(0, 0, displayWidth, displayHeight);
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwSwapBuffers(m_window);
m_unlockFrameRate = true;
}
GLFWwindow *backupContext = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows(); ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault(); ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context); glfwMakeContextCurrent(backupContext);
glfwSwapBuffers(m_window);
// Process layout load requests // Process layout load requests
// NOTE: This needs to be done before a new frame is started, otherwise ImGui won't handle docking correctly // NOTE: This needs to be done before a new frame is started, otherwise ImGui won't handle docking correctly
@ -1029,7 +1048,6 @@ namespace hex {
win->frameBegin(); win->frameBegin();
win->frame(); win->frame();
win->frameEnd(); win->frameEnd();
win->processEvent();
}); });
// Register window resize callback // Register window resize callback
@ -1043,28 +1061,6 @@ namespace hex {
win->frameBegin(); win->frameBegin();
win->frame(); win->frame();
win->frameEnd(); win->frameEnd();
win->processEvent();
});
// Register mouse handling callback
glfwSetMouseButtonCallback(m_window, [](GLFWwindow *window, int button, int action, int mods) {
hex::unused(button, mods);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
if (action == GLFW_PRESS)
win->m_buttonDown = true;
else if (action == GLFW_RELEASE)
win->m_buttonDown = false;
win->processEvent();
});
// Register scrolling callback
glfwSetScrollCallback(m_window, [](GLFWwindow *window, double xOffset, double yOffset) {
hex::unused(xOffset, yOffset);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->processEvent();
}); });
#if !defined(OS_WEB) #if !defined(OS_WEB)
@ -1072,13 +1068,6 @@ namespace hex {
glfwSetKeyCallback(m_window, [](GLFWwindow *window, int key, int scanCode, int action, int mods) { glfwSetKeyCallback(m_window, [](GLFWwindow *window, int key, int scanCode, int action, int mods) {
hex::unused(mods); hex::unused(mods);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
if (action == GLFW_RELEASE) {
win->m_buttonDown = false;
} else {
win->m_buttonDown = true;
}
// Handle A-Z keys using their ASCII value instead of the keycode // Handle A-Z keys using their ASCII value instead of the keycode
if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) { if (key >= GLFW_KEY_A && key <= GLFW_KEY_Z) {
@ -1100,22 +1089,13 @@ namespace hex {
key != GLFW_KEY_LEFT_SHIFT && key != GLFW_KEY_RIGHT_SHIFT && key != GLFW_KEY_LEFT_SHIFT && key != GLFW_KEY_RIGHT_SHIFT &&
key != GLFW_KEY_LEFT_SUPER && key != GLFW_KEY_RIGHT_SUPER key != GLFW_KEY_LEFT_SUPER && key != GLFW_KEY_RIGHT_SUPER
) { ) {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->m_pressedKeys.push_back(key); win->m_pressedKeys.push_back(key);
} }
} }
win->processEvent();
}); });
#endif #endif
// Register cursor position callback
glfwSetCursorPosCallback(m_window, [](GLFWwindow *window, double x, double y) {
hex::unused(x, y);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->processEvent();
});
// Register window close callback // Register window close callback
glfwSetWindowCloseCallback(m_window, [](GLFWwindow *window) { glfwSetWindowCloseCallback(m_window, [](GLFWwindow *window) {
EventWindowClosing::post(window); EventWindowClosing::post(window);