sa2: Add support for --headless and --fixed-speed.
Headless will skip the video refresh (and the vsync). Fixed-Speed will avoid adaptive speed. Used together, the emulator will go at maximum speed skipping video refresh (useful for profiling).
This commit is contained in:
parent
7067ad150e
commit
a121981e5a
7 changed files with 50 additions and 28 deletions
|
@ -39,7 +39,8 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & vers
|
|||
po::options_description emulatorDesc("Emulator");
|
||||
emulatorDesc.add_options()
|
||||
("log", "Log to AppleWin.log")
|
||||
("headless", "Headless: disable video")
|
||||
("headless", "Headless: disable video (freewheel)")
|
||||
("fixed-speed", "Fixed (non-adaptive) speed")
|
||||
("ntsc,nt", "NTSC: execute NTSC code")
|
||||
("benchmark,b", "Benchmark emulator")
|
||||
("no-squaring", "Gamepad range is (already) a square");
|
||||
|
@ -89,6 +90,7 @@ bool getEmulatorOptions(int argc, const char * argv [], const std::string & vers
|
|||
options.log = vm.count("log") > 0;
|
||||
options.ntsc = vm.count("ntsc") > 0;
|
||||
options.squaring = vm.count("no-squaring") == 0;
|
||||
options.fixedSpeed = vm.count("fixed-speed") > 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct EmulatorOptions
|
|||
bool multiThreaded = false;
|
||||
bool looseMutex = false; // whether SDL_UpdateTexture is mutex protected (from CPU)
|
||||
int timerInterval = 16; // only when multithreaded
|
||||
bool fixedSpeed = false; // default adaptive
|
||||
|
||||
int sdlDriver = -1; // default = -1 to let SDL choose
|
||||
};
|
||||
|
|
|
@ -4,32 +4,41 @@
|
|||
#include "CPU.h"
|
||||
#include "AppleWin.h"
|
||||
|
||||
Speed::Speed()
|
||||
: myStartTime(std::chrono::steady_clock::now())
|
||||
Speed::Speed(const bool fixedSpeed)
|
||||
: myFixedSpeed(fixedSpeed)
|
||||
, myStartTime(std::chrono::steady_clock::now())
|
||||
, myStartCycles(g_nCumulativeCycles)
|
||||
{
|
||||
}
|
||||
|
||||
size_t Speed::getCyclesTillNext(const size_t milliseconds) const
|
||||
{
|
||||
const uint64_t currentCycles = g_nCumulativeCycles;
|
||||
const auto currentTime = std::chrono::steady_clock::now();
|
||||
|
||||
const auto currentDelta = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - myStartTime).count();
|
||||
// target the next time we will be called
|
||||
const auto targetDeltaInMillis = currentDelta + milliseconds;
|
||||
|
||||
const uint64_t targetCycles = static_cast<uint64_t>(targetDeltaInMillis * g_fCurrentCLK6502 * 1.0e-3) + myStartCycles;
|
||||
if (targetCycles > currentCycles)
|
||||
if (myFixedSpeed)
|
||||
{
|
||||
// number of cycles to fill this period
|
||||
const uint64_t cyclesToExecute = targetCycles - currentCycles;
|
||||
return cyclesToExecute;
|
||||
const size_t cycles = static_cast<uint64_t>(milliseconds * g_fCurrentCLK6502 * 1.0e-3);
|
||||
return cycles;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we got ahead, nothing to do this time
|
||||
// CpuExecute will still execute 1 instruction, which does not cause any issues
|
||||
return 0;
|
||||
const uint64_t currentCycles = g_nCumulativeCycles;
|
||||
const auto currentTime = std::chrono::steady_clock::now();
|
||||
|
||||
const auto currentDelta = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - myStartTime).count();
|
||||
// target the next time we will be called
|
||||
const auto targetDeltaInMillis = currentDelta + milliseconds;
|
||||
|
||||
const uint64_t targetCycles = static_cast<uint64_t>(targetDeltaInMillis * g_fCurrentCLK6502 * 1.0e-3) + myStartCycles;
|
||||
if (targetCycles > currentCycles)
|
||||
{
|
||||
// number of cycles to fill this period
|
||||
const uint64_t cyclesToExecute = targetCycles - currentCycles;
|
||||
return cyclesToExecute;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we got ahead, nothing to do this time
|
||||
// CpuExecute will still execute 1 instruction, which does not cause any issues
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class Speed
|
||||
{
|
||||
public:
|
||||
Speed();
|
||||
Speed(const bool fixedSpeed);
|
||||
|
||||
// calculate the number of cycles to execute in the current period
|
||||
// assuming the next call will happen in x milliseconds
|
||||
|
@ -13,6 +13,7 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
const bool myFixedSpeed;
|
||||
std::chrono::time_point<std::chrono::steady_clock> myStartTime;
|
||||
uint64_t myStartCycles;
|
||||
};
|
||||
|
|
|
@ -135,13 +135,15 @@ namespace
|
|||
Emulator::Emulator(
|
||||
const std::shared_ptr<SDL_Window> & window,
|
||||
const std::shared_ptr<SDL_Renderer> & renderer,
|
||||
const std::shared_ptr<SDL_Texture> & texture
|
||||
const std::shared_ptr<SDL_Texture> & texture,
|
||||
const bool fixedSpeed
|
||||
)
|
||||
: myWindow(window)
|
||||
, myRenderer(renderer)
|
||||
, myTexture(texture)
|
||||
, myMultiplier(1)
|
||||
, myFullscreen(false)
|
||||
, mySpeed(fixedSpeed)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ public:
|
|||
Emulator(
|
||||
const std::shared_ptr<SDL_Window> & window,
|
||||
const std::shared_ptr<SDL_Renderer> & renderer,
|
||||
const std::shared_ptr<SDL_Texture> & texture
|
||||
const std::shared_ptr<SDL_Texture> & texture,
|
||||
const bool fixedSpeed
|
||||
);
|
||||
|
||||
void execute(const size_t milliseconds);
|
||||
|
|
|
@ -253,7 +253,7 @@ void run_sdl(int argc, const char * argv [])
|
|||
|
||||
const int fps = getRefreshRate();
|
||||
std::cerr << "Video refresh rate: " << fps << " Hz, " << 1000.0 / fps << " ms" << std::endl;
|
||||
Emulator emulator(win, ren, tex);
|
||||
Emulator emulator(win, ren, tex, options.fixedSpeed);
|
||||
|
||||
Timer global;
|
||||
Timer updateTextureTimer;
|
||||
|
@ -318,9 +318,12 @@ void run_sdl(int argc, const char * argv [])
|
|||
SDL_UnlockMutex(data.mutex);
|
||||
}
|
||||
|
||||
refreshScreenTimer.tic();
|
||||
emulator.refreshVideo(rect);
|
||||
refreshScreenTimer.toc();
|
||||
if (!options.headless)
|
||||
{
|
||||
refreshScreenTimer.tic();
|
||||
emulator.refreshVideo(rect);
|
||||
refreshScreenTimer.toc();
|
||||
}
|
||||
|
||||
} while (!quit);
|
||||
|
||||
|
@ -357,9 +360,12 @@ void run_sdl(int argc, const char * argv [])
|
|||
const SDL_Rect rect = emulator.updateTexture();
|
||||
updateTextureTimer.toc();
|
||||
|
||||
refreshScreenTimer.tic();
|
||||
emulator.refreshVideo(rect);
|
||||
refreshScreenTimer.toc();
|
||||
if (!options.headless)
|
||||
{
|
||||
refreshScreenTimer.tic();
|
||||
emulator.refreshVideo(rect);
|
||||
refreshScreenTimer.toc();
|
||||
}
|
||||
} while (!quit);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue