|
Hiccups in main loop that get worse over time |
roger levy
Member #2,513
July 2002
|
My main loop uses a frame timer which I turn off when the display loses focus and re-enable when it comes back. I've noticed a problem where if I step away for an hour or so and come back, I get these long hiccups (stalls) that seem to get longer the longer I wasn't paying attention to the window. I'm not sure if it happens whether or not the display has lost focus, but I may try testing it with the window focused tonight. Has anyone run into this? It doesn't make much sense. I don't know what the system is doing during these stalls. I realized that during these stalls, frames still seem to be processed, just not displayed. So the effect is extreme frame skipping every second for a moment and then smooth action for about a second and then another skip and so on. Forth source: \ Universal main loop \ Skips rendering frames if logic takes too long (up to 4 frames are skipped) \ You can disable the frame timer to save CPU when making editors etc \ When the window is switched away from the timer will be disabled, and re-enabled when \ it regains focus. \ The loop has some common controls: \ F12 - break the loop \ ALT-F4 - quit the process \ ALT-ENTER - toggle fullscreen \ TILDE - toggles a flag called INFO, doesn't do anything on its own. \ Values 0 value #frames \ frame counter. 0 value renderr 0 value steperr 0 value alt? \ part of fix for alt-enter bug when game doesn't have focus 0 value breaking? 0 value lag \ completed ticks 0 value 'go 0 value 'step 0 value 'render \ Flags variable info \ enables debugging mode display variable allowwin allowwin on variable fs \ is fullscreen enabled? variable interact \ if on, cmdline will receive keys. check if false before doing game input, if needed. create fse /ALLEGRO_ANY_EVENT /allot \ fullscreen event #999 constant EVENT_FULLSCREEN : poll pollKB pollJoys [defined] dev [if] pause [then] ; : break true to breaking? ; : -break false to breaking? ; : unmount ( -- ) 1-1 0 0 displayw displayh al_set_clipping_rectangle ALLEGRO_ADD ALLEGRO_ALPHA ALLEGRO_INVERSE_ALPHA ALLEGRO_ADD ALLEGRO_ONE ALLEGRO_ONE al_set_separate_blender display al_set_target_backbuffer ; [defined] dev [if] variable (catch) : try dup -exit sp@ cell+ >r code> catch (catch) ! r> sp! (catch) @ ; [else] : try dup -exit call 0 ; [then] \ : alt? evt ALLEGRO_KEYBOARD_EVENT-modifiers @ ALLEGRO_KEYMOD_ALT and ; : std etype ALLEGRO_EVENT_DISPLAY_RESIZE = if -timer display al_acknowledge_resize +timer \ we have to turn off the timer to avoid a race condition \ where bitmaps aren't recreated before trying to draw to them then etype ALLEGRO_EVENT_DISPLAY_SWITCH_OUT = if -timer -audio then etype ALLEGRO_EVENT_DISPLAY_SWITCH_IN = if clearkb +timer +audio false to alt? eventq al_flush_event_queue [defined] dev [if] interact on [then] then etype ALLEGRO_EVENT_DISPLAY_CLOSE = if 0 ExitProcess then etype ALLEGRO_EVENT_KEY_DOWN = if evt ALLEGRO_KEYBOARD_EVENT-keycode @ case <alt> of true to alt? endof <altgr> of true to alt? endof <enter> of alt? -exit fs toggle endof <f4> of alt? -exit 0 ExitProcess endof <f12> of break endof <tilde> of alt? -exit info toggle endof endcase then etype ALLEGRO_EVENT_KEY_UP = if evt ALLEGRO_KEYBOARD_EVENT-keycode @ case <alt> of false to alt? endof <altgr> of false to alt? endof endcase then ; : fsflag fs @ allowwin @ not or ; : ?fserr 0= if fs off " Fullscreen is not supported by your driver." alert then ; variable winx variable winy : ?poswin \ save/restore window position when toggling in and out of fullscreen display al_get_display_flags ALLEGRO_FULLSCREEN_WINDOW and if fs @ 0= if r> call display winx @ winy @ al_set_window_position then else fs @ if display winx winy al_get_window_position then then ; variable newfs : ?fs ?poswin display ALLEGRO_FULLSCREEN_WINDOW fsflag al_toggle_display_flag ?fserr fs @ newfs @ <> if fse EVENT_FULLSCREEN emit-user-event then fs @ newfs ! ; defer ?overlay ' noop is ?overlay \ render ide defer ?system ' noop is ?system \ system events : render unmount 'render try to renderr ; : step 'step try to steperr ; private: : update? timer? if lag dup -exit drop then eventq al_is_event_queue_empty lag 4 >= or ; : wait eventq evt al_wait_for_event ; : ?render update? -exit 1 +to #frames ?fs render unmount ?overlay al_flip_display 0 to lag ; : ?step etype ALLEGRO_EVENT_TIMER = if 1 +to lag poll step then ; : /ok resetkb -break >display +timer render ; : ok/ eventq al_flush_event_queue -timer >ide -break ; public: : render> r> to 'render ; ( -- <code> ) ( -- ) : step> r> to 'step ; ( -- <code> ) ( -- ) : go> r> to 'go 0 to 'step ; ( -- <code> ) ( -- ) : ok /ok begin wait begin std ?system 'go try drop ?step ?render eventq evt al_get_next_event 0= breaking? or until ?render \ again for sans timer breaking? until ok/ ; :noname 0 0 0.5 clear-to-color ; >code to 'render
|
Chris Katko
Member #1,881
January 2002
|
What OS and what specific version of Allegro? Thanks! Definitely an interesting problem... -----sig: |
roger levy
Member #2,513
July 2002
|
Allegro 5.2.3, Windows 10 |
SiegeLord
Member #7,827
October 2006
|
Try switching between OpenGL and Direct3D. Not sure how you do that in Elvish though... I'll try reproducing it with ex_draw_bitmap 's event loop, although I'm not sure how well that maps to yours. "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
roger levy
Member #2,513
July 2002
|
The principle is pretty simple. Create a timer using the refresh rate retrieved from Allegro. In the event loop, when the timer event fires do game logic and increment a "lag" variable for frame-skipping. When all events are processed, or if lag is over 4, do a render, and reset lag. |
SiegeLord
Member #7,827
October 2006
|
Any luck on your end? I feel like I'll need to learn a bit of Forth to verify that it's not your code. Have you tried calling al_stop_timer instead of just setting timer to false? "For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18 |
roger levy
Member #2,513
July 2002
|
-TIMER and +TIMER actually do stop and restart the timer. Sorry, I didn't include their definitions. (If you don't already know this about Forth, there are no reserved characters except for white space, so those are actually the names of functions I've written.) What I've done is add event logging so the next time I experience the issue (which I haven't yet, strangely) I'll be able to see if a bunch of events are being generated during a hiccup, which is my current theory. |
|