diff options
author | David Robillard <d@drobilla.net> | 2020-10-03 19:38:56 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-10-04 12:52:40 +0200 |
commit | fab3bc3009cca6eb178e11626377492832f49164 (patch) | |
tree | 3dd08db2b8d24236919c1c2745b6cd7f5510ed1d | |
parent | 0b876c3d4e87b65ea3b3f05ec3274b16600e47fc (diff) |
Use refresh rate to better drive example event loop
-rw-r--r-- | examples/pugl_shader_demo.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/examples/pugl_shader_demo.c b/examples/pugl_shader_demo.c index 24ae2a6..70f9c41 100644 --- a/examples/pugl_shader_demo.c +++ b/examples/pugl_shader_demo.c @@ -46,6 +46,7 @@ #include "pugl/pugl.h" #include "pugl/pugl_gl.h" +#include <math.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -71,6 +72,8 @@ typedef struct GLuint vbo; GLuint instanceVbo; GLuint ibo; + double lastDrawDuration; + double lastFrameEndTime; unsigned framesDrawn; int glMajorVersion; int glMinorVersion; @@ -137,6 +140,9 @@ onExpose(PuglView* view) (GLsizei)(app->numRects * 4)); ++app->framesDrawn; + + app->lastFrameEndTime = puglGetTime(puglGetWorld(view)); + app->lastDrawDuration = app->lastFrameEndTime - time; } static PuglStatus @@ -408,10 +414,35 @@ main(int argc, char** argv) printViewHints(app.view); puglShowWindow(app.view); + // Calculate ideal frame duration to drive the main loop at a good rate + const int refreshRate = puglGetViewHint(app.view, PUGL_REFRESH_RATE); + const double frameDuration = 1.0 / (double)refreshRate; + // Grind away, drawing continuously - PuglFpsPrinter fpsPrinter = {puglGetTime(app.world)}; + const double startTime = puglGetTime(app.world); + PuglFpsPrinter fpsPrinter = {startTime}; while (!app.quit) { - puglUpdate(app.world, 0.0); + /* To minimize input latency and get smooth performance during window + resizing, we want to poll for events as long as possible before + starting to draw the next frame. This ensures that as many events + are consumed as possible before starting to draw, or, equivalently, + that the next rendered frame represents the latest events possible. + This is particularly important for mouse input and "live" window + resizing, where many events tend to pile up within a frame. + + To do this, we keep track of the time when the last frame was + finished drawing, and how long it took to expose (and assume this is + relatively stable). Then, we can calculate how much time there is + from now until the time when we should start drawing to not miss the + deadline, and use that as the timeout for puglUpdate(). + */ + + const double now = puglGetTime(app.world); + const double nextFrameEndTime = app.lastFrameEndTime + frameDuration; + const double nextExposeTime = nextFrameEndTime - app.lastDrawDuration; + const double timeout = fmax(0.0, nextExposeTime - now); + + puglUpdate(app.world, timeout); puglPrintFps(app.world, &fpsPrinter, &app.framesDrawn); } |