Finally implemented pause functionality. It is only enabled in X11 and SDL

versions for now, but can easily be used in other ports.  Press the PAUSE button
to activate and deactivate.

It is started by calling Console.mediaSource().pause(bool state), where state
is either true or false and will enable/disable the pause, respectively.

When pause is enabled, a mute is sent to the Sound device, so other ports must
have coded this Sound::mute method.  While pause is on, all calls to
Console.mediaSource().update() will do nothing.  Only by calling pause() again
can the emulator proceed.

Other ports will probably require a minor rewrite of their main loop, since
the calculation of frames per second will now have to be done differently.

Previously, FPS was based on the time entering the main loop and the time
leaving.  This difference was the total time used in calculating FPS.
Now, since pause can be on for an indefinite amount of time, the total time must
be incremented *per frame* instead of over the whole loop.  Similarly, the total
number of frames drawn is no longer how many times you pass through the loop, but
how many times you pass through the loop *while not paused*.

See ui/sdl/mainSDL.cxx or ui/x11/mainX11.cxx for more info.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@47 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2002-03-17 19:37:00 +00:00
parent c67481c440
commit bf6138c256
6 changed files with 142 additions and 60 deletions

View File

@ -13,7 +13,7 @@
## See the file "license" for information on usage and redistribution of ## See the file "license" for information on usage and redistribution of
## this file, and for a DISCLAIMER OF ALL WARRANTIES. ## this file, and for a DISCLAIMER OF ALL WARRANTIES.
## ##
## $Id: makefile,v 1.10 2002-03-10 01:29:54 stephena Exp $ ## $Id: makefile,v 1.11 2002-03-17 19:37:00 stephena Exp $
##============================================================================ ##============================================================================
##============================================================================ ##============================================================================
@ -34,7 +34,7 @@ OPTIMIZATIONS =
# -funroll-loops -fstrength-reduce -fomit-frame-pointer -ffast-math \ # -funroll-loops -fstrength-reduce -fomit-frame-pointer -ffast-math \
# -malign-functions=2 -malign-jumps=2 -malign-loops=2 # -malign-functions=2 -malign-jumps=2 -malign-loops=2
### to get full optimization under gcc/x Athlon based OS's.. ### to get full optimization under gcc/x Athlon based OS's..
# OPTIMIZATIONS = -O3 -march=athlon -Wall -Wno-unused \ # OPTIMIZATIONS = -O3 -mcpu=athlon -march=athlon -Wall -Wno-unused \
# -funroll-loops -fstrength-reduce -fomit-frame-pointer -ffast-math \ # -funroll-loops -fstrength-reduce -fomit-frame-pointer -ffast-math \
# -malign-functions=2 -malign-jumps=2 -malign-loops=2 # -malign-functions=2 -malign-jumps=2 -malign-loops=2

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: MediaSrc.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $ // $Id: MediaSrc.hxx,v 1.2 2002-03-17 19:37:00 stephena Exp $
//============================================================================ //============================================================================
#ifndef MEDIASOURCE_HXX #ifndef MEDIASOURCE_HXX
@ -27,7 +27,7 @@ class MediaSource;
This class provides an interface for accessing graphics data. This class provides an interface for accessing graphics data.
@author Bradford W. Mott @author Bradford W. Mott
@version $Id: MediaSrc.hxx,v 1.1.1.1 2001-12-27 19:54:22 bwmott Exp $ @version $Id: MediaSrc.hxx,v 1.2 2002-03-17 19:37:00 stephena Exp $
*/ */
class MediaSource class MediaSource
{ {
@ -49,6 +49,15 @@ class MediaSource
*/ */
virtual void update() = 0; virtual void update() = 0;
/**
This method should be called to cause further calls to 'update'
to be ignored until an unpause is given. Will also send a mute to
the Sound device.
@return Status of the pause, success (true) or failure (false)
*/
virtual bool pause(bool state) = 0;
/** /**
Answers the current frame buffer Answers the current frame buffer
@ -102,4 +111,3 @@ class MediaSource
MediaSource& operator = (const MediaSource&); MediaSource& operator = (const MediaSource&);
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: TIA.cxx,v 1.6 2002-01-27 02:10:04 stephena Exp $ // $Id: TIA.cxx,v 1.7 2002-03-17 19:37:00 stephena Exp $
//============================================================================ //============================================================================
#include <assert.h> #include <assert.h>
@ -262,6 +262,10 @@ void TIA::install(System& system)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::update() void TIA::update()
{ {
// Don't do an update if the emulator is paused
if(pauseState)
return;
uInt8* tmp = myCurrentFrameBuffer; uInt8* tmp = myCurrentFrameBuffer;
myCurrentFrameBuffer = myPreviousFrameBuffer; myCurrentFrameBuffer = myPreviousFrameBuffer;
myPreviousFrameBuffer = tmp; myPreviousFrameBuffer = tmp;
@ -295,6 +299,21 @@ void TIA::update()
myScanlineCountForFrame = totalClocks / 228; myScanlineCountForFrame = totalClocks / 228;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::pause(bool state)
{
// Ignore multiple calls to do the same thing
if(pauseState == state)
return false;
pauseState = state;
// Now pause the Sound device
mySound.mute(pauseState);
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const uInt32* TIA::palette() const const uInt32* TIA::palette() const
{ {

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: TIA.hxx,v 1.1.1.1 2001-12-27 19:54:25 bwmott Exp $ // $Id: TIA.hxx,v 1.2 2002-03-17 19:37:00 stephena Exp $
//============================================================================ //============================================================================
#ifndef TIA_HXX #ifndef TIA_HXX
@ -38,7 +38,7 @@ class System;
be displayed on screen. be displayed on screen.
@author Bradford W. Mott @author Bradford W. Mott
@version $Id: TIA.hxx,v 1.1.1.1 2001-12-27 19:54:25 bwmott Exp $ @version $Id: TIA.hxx,v 1.2 2002-03-17 19:37:00 stephena Exp $
*/ */
class TIA : public Device , public MediaSource class TIA : public Device , public MediaSource
{ {
@ -106,6 +106,15 @@ class TIA : public Device , public MediaSource
*/ */
virtual void update(); virtual void update();
/**
This method should be called to cause further calls to 'update'
to be ignored until an unpause is given. Will also send a mute to
the Sound device.
@return Status of the pause, success (true) or failure (false)
*/
virtual bool pause(bool state);
/** /**
Answers the current frame buffer Answers the current frame buffer
@ -417,6 +426,8 @@ class TIA : public Device , public MediaSource
// Assignment operator isn't supported by this class so make it private // Assignment operator isn't supported by this class so make it private
TIA& operator = (const TIA&); TIA& operator = (const TIA&);
// Indicates whether the current emulation cycle should is paused
bool pauseState;
}; };
#endif #endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainSDL.cxx,v 1.12 2002-03-10 01:29:55 stephena Exp $ // $Id: mainSDL.cxx,v 1.13 2002-03-17 19:37:00 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
@ -49,6 +49,7 @@
#define SDL_DISABLE 0 #define SDL_DISABLE 0
#endif #endif
#define HAVE_GETTIMEOFDAY
SDL_Joystick* theLeftJoystick; SDL_Joystick* theLeftJoystick;
SDL_Joystick* theRightJoystick; SDL_Joystick* theRightJoystick;
@ -73,6 +74,7 @@ void toggleFullscreen();
void takeSnapshot(); void takeSnapshot();
void togglePause(); void togglePause();
uInt32 maxWindowSizeForScreen(); uInt32 maxWindowSizeForScreen();
uInt32 getTicks();
bool setupProperties(PropertiesSet& set); bool setupProperties(PropertiesSet& set);
void handleCommandLineArguments(int ac, char* av[]); void handleCommandLineArguments(int ac, char* av[]);
@ -608,8 +610,6 @@ void toggleFullscreen()
*/ */
void togglePause() void togglePause()
{ {
// todo: implement pause functionality
if(thePauseIndicator) // emulator is already paused so continue if(thePauseIndicator) // emulator is already paused so continue
{ {
thePauseIndicator = false; thePauseIndicator = false;
@ -618,6 +618,8 @@ void togglePause()
{ {
thePauseIndicator = true; thePauseIndicator = true;
} }
theConsole->mediaSource().pause(thePauseIndicator);
} }
@ -961,8 +963,7 @@ void handleEvents()
{ {
if(!thePauseIndicator) if(!thePauseIndicator)
{ {
// togglePause(); togglePause();
cerr << "todo: Pause on minimize.\n";
} }
} }
} }
@ -1673,13 +1674,13 @@ int main(int argc, char* argv[])
cleanup(); cleanup();
} }
// Get the starting time in case we need to print statistics // Set up timing stuff
timeval startingTime; Uint32 before, delta, frameTime = 0, eventTime = 0;
gettimeofday(&startingTime, 0); Uint32 timePerFrame = 1000000 / theDesiredFrameRate;
Uint32 numberOfFrames = 0;
uInt32 numberOfFrames = 0; // Main game loop
uInt32 frameTime = 1000000 / theDesiredFrameRate; for(;;)
for( ; ; ++numberOfFrames)
{ {
// Exit if the user wants to quit // Exit if the user wants to quit
if(theQuitIndicator) if(theQuitIndicator)
@ -1687,36 +1688,37 @@ int main(int argc, char* argv[])
break; break;
} }
// Remember the current time before we start drawing the frame // Call handleEvents here to see if user pressed pause
timeval before; handleEvents();
gettimeofday(&before, 0); if(thePauseIndicator)
{
updateDisplay(theConsole->mediaSource());
SDL_Delay(10);
continue;
}
before = getTicks();
theConsole->mediaSource().update(); theConsole->mediaSource().update();
updateDisplay(theConsole->mediaSource()); updateDisplay(theConsole->mediaSource());
handleEvents(); handleEvents();
// Now, waste time if we need to so that we are at the desired frame rate // Now, waste time if we need to so that we are at the desired frame rate
timeval after;
for(;;) for(;;)
{ {
gettimeofday(&after, 0); delta = getTicks() - before;
uInt32 delta = (uInt32)((after.tv_sec - before.tv_sec) * 1000000 + if(delta >= timePerFrame)
(after.tv_usec - before.tv_usec));
if(delta > frameTime)
break; break;
//else SDL_Delay(1);
} }
frameTime += (getTicks() - before);
++numberOfFrames;
} }
if(theShowInfoFlag) if(theShowInfoFlag)
{ {
timeval endingTime; double executionTime = (double) frameTime / 1000000.0;
gettimeofday(&endingTime, 0); double framesPerSecond = (double) numberOfFrames / executionTime;
double executionTime = (endingTime.tv_sec - startingTime.tv_sec) +
((endingTime.tv_usec - startingTime.tv_usec) / 1000000.0);
double framesPerSecond = numberOfFrames / executionTime;
cout << endl; cout << endl;
cout << numberOfFrames << " total frames drawn\n"; cout << numberOfFrames << " total frames drawn\n";
@ -1732,3 +1734,24 @@ int main(int argc, char* argv[])
// Cleanup time ... // Cleanup time ...
cleanup(); cleanup();
} }
/**
Returns number of ticks in microseconds
*/
#ifdef HAVE_GETTIMEOFDAY
inline uInt32 getTicks()
{
timeval now;
gettimeofday(&now, 0);
uInt32 ticks = now.tv_sec * 1000000 + now.tv_usec;
return ticks;
}
#else
inline uInt32 getTicks()
{
return SDL_GetTicks() * 1000;
}
#endif

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of // See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
// //
// $Id: mainX11.cxx,v 1.13 2002-03-12 19:27:11 stephena Exp $ // $Id: mainX11.cxx,v 1.14 2002-03-17 19:37:00 stephena Exp $
//============================================================================ //============================================================================
#include <fstream> #include <fstream>
@ -66,6 +66,8 @@
int theRightJoystickFd; int theRightJoystickFd;
#endif #endif
#define HAVE_GETTIMEOFDAY
// Globals for X windows stuff // Globals for X windows stuff
Display* theDisplay; Display* theDisplay;
string theDisplayName = ""; string theDisplayName = "";
@ -99,6 +101,7 @@ void toggleFullscreen();
void takeSnapshot(); void takeSnapshot();
void togglePause(); void togglePause();
uInt32 maxWindowSizeForScreen(); uInt32 maxWindowSizeForScreen();
uInt32 getTicks();
bool setupProperties(PropertiesSet& set); bool setupProperties(PropertiesSet& set);
void handleCommandLineArguments(int argc, char* argv[]); void handleCommandLineArguments(int argc, char* argv[]);
@ -686,8 +689,7 @@ void handleEvents()
{ {
if(!thePauseIndicator) if(!thePauseIndicator)
{ {
// togglePause(); togglePause();
cerr << "todo: Pause on minimize.\n";
} }
} }
} }
@ -922,8 +924,6 @@ void toggleFullscreen()
*/ */
void togglePause() void togglePause()
{ {
// todo: implement pause functionality
if(thePauseIndicator) // emulator is already paused so continue if(thePauseIndicator) // emulator is already paused so continue
{ {
thePauseIndicator = false; thePauseIndicator = false;
@ -932,6 +932,8 @@ void togglePause()
{ {
thePauseIndicator = true; thePauseIndicator = true;
} }
theConsole->mediaSource().pause(thePauseIndicator);
} }
/** /**
@ -1574,13 +1576,13 @@ int main(int argc, char* argv[])
cleanup(); cleanup();
} }
// Get the starting time in case we need to print statistics // Set up timing stuff
timeval startingTime; uInt32 before, delta, frameTime = 0, eventTime = 0;
gettimeofday(&startingTime, 0); uInt32 timePerFrame = 1000000 / theDesiredFrameRate;
uInt32 numberOfFrames = 0; uInt32 numberOfFrames = 0;
uInt32 frameTime = 1000000 / theDesiredFrameRate;
for( ; ; ++numberOfFrames) // Main game loop
for(;;)
{ {
// Exit if the user wants to quit // Exit if the user wants to quit
if(theQuitIndicator) if(theQuitIndicator)
@ -1588,35 +1590,37 @@ int main(int argc, char* argv[])
break; break;
} }
// Remember the current time before we start drawing the frame // Call handleEvents here to see if user pressed pause
timeval before; handleEvents();
gettimeofday(&before, 0); if(thePauseIndicator)
{
updateDisplay(theConsole->mediaSource());
usleep(10000);
continue;
}
before = getTicks();
theConsole->mediaSource().update(); theConsole->mediaSource().update();
updateDisplay(theConsole->mediaSource()); updateDisplay(theConsole->mediaSource());
handleEvents(); handleEvents();
// Now, waste time if we need to so that we are at the desired frame rate // Now, waste time if we need to so that we are at the desired frame rate
timeval after;
for(;;) for(;;)
{ {
gettimeofday(&after, 0); delta = getTicks() - before;
uInt32 delta = (uInt32)((after.tv_sec - before.tv_sec) * 1000000 + if(delta > timePerFrame)
(after.tv_usec - before.tv_usec));
if(delta > frameTime)
break; break;
} }
frameTime += (getTicks() - before);
++numberOfFrames;
} }
if(theShowInfoFlag) if(theShowInfoFlag)
{ {
timeval endingTime; double executionTime = (double) frameTime / 1000000.0;
gettimeofday(&endingTime, 0); double framesPerSecond = (double) numberOfFrames / executionTime;
double executionTime = (endingTime.tv_sec - startingTime.tv_sec) +
((endingTime.tv_usec - startingTime.tv_usec) / 1000000.0);
double framesPerSecond = numberOfFrames / executionTime;
cout << endl; cout << endl;
cout << numberOfFrames << " total frames drawn\n"; cout << numberOfFrames << " total frames drawn\n";
@ -1633,3 +1637,20 @@ int main(int argc, char* argv[])
cleanup(); cleanup();
return 0; return 0;
} }
/**
Returns number of ticks in microseconds
*/
#ifdef HAVE_GETTIMEOFDAY
inline uInt32 getTicks()
{
timeval now;
gettimeofday(&now, 0);
uInt32 ticks = now.tv_sec * 1000000 + now.tv_usec;
return ticks;
}
#else
#error "We need gettimeofday for the X11 version"
#endif