Skip to content

Commit 44f0ce8

Browse files
committed
improve handling of fps limits with frameTick()
1 parent 1a8b54b commit 44f0ce8

File tree

4 files changed

+59
-19
lines changed

4 files changed

+59
-19
lines changed

examples/demo-app/demo_app.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -944,11 +944,12 @@ int main(int argc, char** argv) {
944944
} else {
945945
// Show the gui
946946
polyscope::show();
947+
948+
// main loop using manual frameTick() instead
949+
// while (!polyscope::windowRequestsClose()) {
950+
// polyscope::frameTick();
951+
// }
947952
}
948-
// main loop using manual frameTick() instead
949-
// while (true) {
950-
// polyscope::frameTick();
951-
// }
952953

953954
std::cout << "!!!! shutdown time" << std::endl;
954955
polyscope::shutdown();

include/polyscope/options.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ extern int maxFPS;
4141
// NOTE: some platforms may ignore the setting.
4242
extern bool enableVSync;
4343

44+
// When using the alternate `frameTick()` control flow instead of `show()`, should framerate-limiting maxFPS/vsync
45+
// features be respected? (which might caues the program to block on the call to frameTick()). (default: false)
46+
extern bool frameTickLimitFPS;
47+
4448
// Read preferences (window size, etc) from startup file, write to same file on exit (default: true)
4549
extern bool usePrefsFile;
4650

src/options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ bool allowHeadlessBackends = false;
1313
bool errorsThrowExceptions = false;
1414
bool debugDrawPickBuffer = false;
1515
int maxFPS = 60;
16-
1716
#ifdef _WIN32
1817
// set the default vsync to false on windows, to workaround an glfw errors from an alleged driver bug
1918
bool enableVSync = false;
2019
#else
2120
bool enableVSync = true;
2221
#endif
22+
bool frameTickLimitFPS = false;
2323

2424
bool usePrefsFile = true;
2525
bool initializeWithDefaultStructures = true;

src/polyscope.cpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,22 @@ std::map<std::string, std::unique_ptr<Structure>>& getStructureMapCreateIfNeeded
153153
return state::structures[typeName];
154154
}
155155

156+
void sleepForFramerate() {
157+
// If needed, block the program execution to hit the intended framerate
158+
// (if not used, the render loop may busy-run maxed out at 1000+ fps and waste resources)
159+
if (options::maxFPS != -1) {
160+
auto currTime = std::chrono::steady_clock::now();
161+
long microsecPerLoop = 1000000 / options::maxFPS;
162+
microsecPerLoop = (95 * microsecPerLoop) / 100; // give a little slack so we actually hit target fps
163+
while (std::chrono::duration_cast<std::chrono::microseconds>(currTime - lastMainLoopIterTime).count() <
164+
microsecPerLoop) {
165+
std::this_thread::yield();
166+
currTime = std::chrono::steady_clock::now();
167+
}
168+
}
169+
lastMainLoopIterTime = std::chrono::steady_clock::now();
170+
}
171+
156172
} // namespace
157173

158174
// === Core global functions
@@ -239,19 +255,7 @@ void pushContext(std::function<void()> callbackFunction, bool drawDefaultUI) {
239255
size_t currentContextStackSize = contextStack.size();
240256
while (contextStack.size() >= currentContextStackSize) {
241257

242-
// The windowing system will let the main loop busy-loop on some platforms. Make sure that doesn't happen.
243-
if (options::maxFPS != -1) {
244-
auto currTime = std::chrono::steady_clock::now();
245-
long microsecPerLoop = 1000000 / options::maxFPS;
246-
microsecPerLoop = (95 * microsecPerLoop) / 100; // give a little slack so we actually hit target fps
247-
while (std::chrono::duration_cast<std::chrono::microseconds>(currTime - lastMainLoopIterTime).count() <
248-
microsecPerLoop) {
249-
std::this_thread::yield();
250-
currTime = std::chrono::steady_clock::now();
251-
}
252-
}
253-
lastMainLoopIterTime = std::chrono::steady_clock::now();
254-
258+
sleepForFramerate();
255259
mainLoopIteration();
256260

257261
// auto-exit if the window is closed
@@ -305,9 +309,29 @@ void frameTick() {
305309
// Make sure we're visible
306310
render::engine->showWindow();
307311

308-
// All-imporant main loop iteration
312+
bool savedVsyncValue = false; // see below
313+
bool needToRestoreVSyncValue =
314+
false; // we need this as a saved bool, because the setting could change during mainLoopIteration()
315+
if (options::frameTickLimitFPS) {
316+
sleepForFramerate();
317+
} else {
318+
// Ugly workaround to preserve the API:
319+
// We want vsync to be disabled unless frameTick(limitFPS=True), so that we don't slow down user's application.
320+
// But it's currently a bool read in the render call and I don't want to change that API. So we temporarily set
321+
// it to false and restore the value after.
322+
// ONEDAY: when we have a major version update, change the API on the vsync setting to make this unecessary
323+
savedVsyncValue = options::enableVSync;
324+
options::enableVSync = false;
325+
needToRestoreVSyncValue = true;
326+
}
327+
309328
mainLoopIteration();
310329

330+
if (needToRestoreVSyncValue) {
331+
// restore saved value, see note above
332+
options::enableVSync = savedVsyncValue;
333+
}
334+
311335
frameTickStack--;
312336
}
313337

@@ -705,6 +729,15 @@ void buildPolyscopeGui() {
705729
ImGui::Text("Last: %.1f ms/frame (%.1f fps)", ImGui::GetIO().DeltaTime * 1000.f, 1.f / ImGui::GetIO().DeltaTime);
706730

707731
ImGui::PushItemWidth(40 * options::uiScale);
732+
733+
bool isFrameTickShow = frameTickStack > 0;
734+
if (isFrameTickShow) {
735+
ImGui::Checkbox("limit fps", &options::frameTickLimitFPS);
736+
ImGui::SameLine();
737+
}
738+
739+
ImGui::BeginDisabled(isFrameTickShow && !options::frameTickLimitFPS);
740+
708741
if (ImGui::InputInt("max fps", &options::maxFPS, 0)) {
709742
if (options::maxFPS < 1 && options::maxFPS != -1) {
710743
options::maxFPS = -1;
@@ -715,6 +748,8 @@ void buildPolyscopeGui() {
715748
ImGui::SameLine();
716749
ImGui::Checkbox("vsync", &options::enableVSync);
717750

751+
ImGui::EndDisabled();
752+
718753
ImGui::TreePop();
719754
}
720755

0 commit comments

Comments
 (0)