diff --git a/sc2/ChangeLog b/sc2/ChangeLog index a61629c20..e9f7f8b2f 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,6 @@ Changes towards version 0.7: +- Thread down-throttling and game sleep when inactive (currently disabled), + (bug #1070), from Flandry - Internal changes: GOOD_GUY/BAD_GUY ship flags retired - Alex - Fixed Melee menu timeout when both sides are Cyborgs (bug #1067) - Alex - Fixed AI ship not moving on warp in (bug #648) - Alex diff --git a/sc2/src/libs/graphics/sdl/sdl_common.c b/sc2/src/libs/graphics/sdl/sdl_common.c index ba634f3e5..f68357347 100644 --- a/sc2/src/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/libs/graphics/sdl/sdl_common.c @@ -56,6 +56,7 @@ TFB_GRAPHICS_BACKEND *graphics_backend = NULL; int RenderedFrames = 0; volatile int QuitPosted = 0; +volatile int GameActive = 1; // Track the SDL_ACTIVEEVENT state SDL_APPACTIVE void TFB_PreInit (void) @@ -198,10 +199,19 @@ TFB_ProcessEvents () { /* Run through the InputEvent filter. */ ProcessInputEvent (&Event); - /* Handle Graphics events. */ + /* Handle graphics and exposure events. */ switch (Event.type) { - case SDL_ACTIVEEVENT: /* Lose/gain visibility */ - // TODO + case SDL_ACTIVEEVENT: /* Lose/gain visibility or focus */ + /* Up to three different state changes can occur in one event. */ + /* Here, disregard least significant change (mouse focus). */ +#if 0 /* Currently disabled in mainline */ + // This controls the automatic sleep/pause when minimized. + // On small displays (e.g. mobile devices), APPINPUTFOCUS would + // be an appropriate substitution for APPACTIVE: + // if (Event.active.state & SDL_APPINPUTFOCUS) + if (Event.active.state & SDL_APPACTIVE) + GameActive = Event.active.gain; +#endif break; case SDL_QUIT: QuitPosted = 1; diff --git a/sc2/src/libs/inplib.h b/sc2/src/libs/inplib.h index e7b238773..5669281b7 100644 --- a/sc2/src/libs/inplib.h +++ b/sc2/src/libs/inplib.h @@ -37,6 +37,7 @@ extern BYTE LocateMouse (SWORD *px, SWORD *py); extern volatile int MouseButtonDown; extern volatile int QuitPosted; +extern volatile int GameActive; /* Functions for dealing with Character Mode */ diff --git a/sc2/src/libs/sound/stream.c b/sc2/src/libs/sound/stream.c index cabe24a07..fde4c4af4 100644 --- a/sc2/src/libs/sound/stream.c +++ b/sc2/src/libs/sound/stream.c @@ -495,11 +495,12 @@ int StreamDecoderTaskFunc (void *data) { Task task = (Task)data; + int active_streams; int i; while (!Task_ReadState (task, TASK_EXIT)) { - TaskSwitch (); + active_streams = 0; for (i = MUSIC_SOURCE; i < NUM_SOUNDSOURCES; ++i) { @@ -517,9 +518,17 @@ StreamDecoderTaskFunc (void *data) } process_stream (source); + active_streams++; UnlockMutex (source->stream_mutex); } + + if (active_streams == 0) + { // Throttle down the thread when there are no active streams + SleepThread (ONE_SECOND / 10); + } + else + TaskSwitch (); } FinishTask (task); diff --git a/sc2/src/uqm.c b/sc2/src/uqm.c index 8172a4d78..068b9a2ad 100644 --- a/sc2/src/uqm.c +++ b/sc2/src/uqm.c @@ -433,6 +433,10 @@ main (int argc, char *argv[]) SignalStopMainThread (); ++i; } + else if (!GameActive) + { // Throttle down the main loop when game is inactive + SleepThread (ONE_SECOND / 4); + } TFB_ProcessEvents (); ProcessUtilityKeys (); diff --git a/sc2/src/uqm/controls.h b/sc2/src/uqm/controls.h index 27d9a011e..28195adbf 100644 --- a/sc2/src/uqm/controls.h +++ b/sc2/src/uqm/controls.h @@ -100,6 +100,7 @@ void SetMenuRepeatDelay (DWORD min, DWORD max, DWORD step, BOOLEAN gestalt); void SetDefaultMenuRepeatDelay (void); void ResetKeyRepeat (void); BOOLEAN PauseGame (void); +void SleepGame (void); BOOLEAN DoConfirmExit (void); BOOLEAN WaitAnyButtonOrQuit (BOOLEAN CheckSpecial); void WaitForNoInput (SIZE Duration); diff --git a/sc2/src/uqm/gameinp.c b/sc2/src/uqm/gameinp.c index 16795fe9f..6b93aac5e 100644 --- a/sc2/src/uqm/gameinp.c +++ b/sc2/src/uqm/gameinp.c @@ -228,6 +228,11 @@ UpdateInputState (void) * UpdateInputState routinely, so we handle pause and exit * state updates here. */ + // Automatically pause and enter low-activity state while inactive, + // for example, window minimized. + if (!GameActive) + SleepGame (); + if (GamePaused) PauseGame (); diff --git a/sc2/src/uqm/starcon.c b/sc2/src/uqm/starcon.c index 8543ce94c..55f00dfc6 100644 --- a/sc2/src/uqm/starcon.c +++ b/sc2/src/uqm/starcon.c @@ -106,6 +106,7 @@ SignalStopMainThread (void) { GamePaused = FALSE; GLOBAL (CurrentActivity) |= CHECK_ABORT; + TaskSwitch (); } void diff --git a/sc2/src/uqm/util.c b/sc2/src/uqm/util.c index 0d15724b3..fe221f60a 100644 --- a/sc2/src/uqm/util.c +++ b/sc2/src/uqm/util.c @@ -20,9 +20,11 @@ #include "controls.h" #include "util.h" #include "setup.h" +#include "settings.h" #include "libs/inplib.h" #include "libs/sound/trackplayer.h" #include "libs/mathlib.h" +#include "libs/log.h" void @@ -250,3 +252,43 @@ WaitAnyButtonOrQuit (BOOLEAN CheckSpecial) return (GLOBAL (CurrentActivity) & CHECK_ABORT) != 0; } +// Stops game clock and music thread and minimizes interrupts/cycles +// based on value of global GameActive variable +// See similar sleep state for main thread in uqm.c:main() +void +SleepGame (void) +{ + if (QuitPosted) + return; // Do not sleep the game when already asked to quit + + log_add (log_Debug, "Game is going to sleep"); + + if (LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE && + LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE) + SuspendGameClock (); + if (CommData.ConversationPhrases && PlayingTrack ()) + PauseTrack (); + PauseMusic (); + + LockMutex (GraphicsLock); + + while (!GameActive && !QuitPosted) + SleepThread (ONE_SECOND / 2); + + log_add (log_Debug, "Game is waking up"); + + WaitForNoInput (ONE_SECOND / 10); + FlushInput (); + + ResumeMusic (); + + if (LOBYTE (GLOBAL (CurrentActivity)) != SUPER_MELEE && + LOBYTE (GLOBAL (CurrentActivity)) != WON_LAST_BATTLE) + ResumeGameClock (); + if (CommData.ConversationPhrases && PlayingTrack ()) + ResumeTrack (); + + UnlockMutex (GraphicsLock); + + TaskSwitch (); +}