impr: Implement rendering power saving using hashes
This commit is contained in:
parent
1cf692cecf
commit
e414c1cf1e
@ -38,8 +38,6 @@ namespace hex {
|
||||
void frame();
|
||||
void frameEnd();
|
||||
|
||||
void processEvent() { m_hadEvent = true; }
|
||||
|
||||
void initGLFW();
|
||||
void initImGui();
|
||||
void exitGLFW();
|
||||
@ -60,11 +58,7 @@ namespace hex {
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
std::vector<int> m_pressedKeys;
|
||||
|
||||
bool m_buttonDown = false;
|
||||
|
||||
bool m_hadEvent = false;
|
||||
bool m_frameRateTemporarilyUnlocked = false;
|
||||
double m_frameRateUnlockTime = 0;
|
||||
bool m_unlockFrameRate = false;
|
||||
|
||||
ImGuiExt::ImHexCustomData m_imguiCustomData;
|
||||
};
|
||||
|
@ -174,38 +174,30 @@ namespace hex {
|
||||
while (!glfwWindowShouldClose(m_window)) {
|
||||
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 the application is minimized or not visible, don't render anything
|
||||
glfwWaitEvents();
|
||||
} else {
|
||||
// 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
|
||||
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 ((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)
|
||||
if (shouldLongSleep)
|
||||
glfwWaitEventsTimeout(timeout);
|
||||
}
|
||||
}
|
||||
@ -223,7 +215,7 @@ namespace hex {
|
||||
} else if (targetFPS > 200) {
|
||||
glfwSwapInterval(0);
|
||||
} else {
|
||||
if (m_frameRateTemporarilyUnlocked) {
|
||||
if (!shouldLongSleep) {
|
||||
glfwSwapInterval(0);
|
||||
const auto frameTime = glfwGetTime() - m_lastStartFrameTime;
|
||||
const auto targetFrameTime = 1.0 / targetFPS;
|
||||
@ -889,9 +881,33 @@ namespace hex {
|
||||
|
||||
this->endNativeWindowFrame();
|
||||
|
||||
// Render UI
|
||||
// Finalize ImGui frame
|
||||
ImGui::Render();
|
||||
|
||||
// Hash the draw data to determine if anything changed on the screen
|
||||
// If not, there's no point in sending the draw data off to the GPU and swapping buffers
|
||||
bool shouldRender = false;
|
||||
{
|
||||
u32 drawDataHash = 0;
|
||||
static u32 previousDrawDataHash = 0;
|
||||
|
||||
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);
|
||||
@ -899,12 +915,15 @@ namespace hex {
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
GLFWwindow *backup_current_context = glfwGetCurrentContext();
|
||||
glfwSwapBuffers(m_window);
|
||||
|
||||
m_unlockFrameRate = true;
|
||||
}
|
||||
|
||||
GLFWwindow *backupContext = glfwGetCurrentContext();
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui::RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
|
||||
glfwSwapBuffers(m_window);
|
||||
glfwMakeContextCurrent(backupContext);
|
||||
|
||||
// Process layout load requests
|
||||
// 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->frame();
|
||||
win->frameEnd();
|
||||
win->processEvent();
|
||||
});
|
||||
|
||||
// Register window resize callback
|
||||
@ -1043,28 +1061,6 @@ namespace hex {
|
||||
win->frameBegin();
|
||||
win->frame();
|
||||
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)
|
||||
@ -1072,13 +1068,6 @@ namespace hex {
|
||||
glfwSetKeyCallback(m_window, [](GLFWwindow *window, int key, int scanCode, int action, int 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
|
||||
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_SUPER && key != GLFW_KEY_RIGHT_SUPER
|
||||
) {
|
||||
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
||||
win->m_pressedKeys.push_back(key);
|
||||
}
|
||||
}
|
||||
|
||||
win->processEvent();
|
||||
});
|
||||
#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
|
||||
glfwSetWindowCloseCallback(m_window, [](GLFWwindow *window) {
|
||||
EventWindowClosing::post(window);
|
||||
|
Loading…
x
Reference in New Issue
Block a user