Rewrite the way full speed works.

This is more and more similar to AppleWin's logic.

Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
This commit is contained in:
Andrea Odetti 2021-06-07 18:34:17 +01:00
parent 24971328ba
commit 0b3e57d934
9 changed files with 100 additions and 79 deletions

View file

@ -27,7 +27,7 @@ namespace common2
uint64_t Speed::getCyclesTillNext(const size_t microseconds) const
{
if (myFixedSpeed)
if (myFixedSpeed || g_bFullSpeed)
{
return getCyclesAtFixedSpeed(microseconds);
}

View file

@ -133,12 +133,14 @@ namespace sa2
{
if (ImGui::Begin("Apple ]["))
{
UpdateTexture();
ImGui::Image(myTexture, ImGui::GetContentRegionAvail(), uv0, uv1);
}
ImGui::End();
}
else
{
UpdateTexture();
const ImVec2 zero(0, menuBarHeight);
// draw on the background
ImGuiIO& io = ImGui::GetIO();
@ -159,7 +161,7 @@ namespace sa2
y = GetRelativePosition(posY, height);
}
void SDLImGuiFrame::RenderPresent()
void SDLImGuiFrame::VideoPresentScreen()
{
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(myWindow.get());

View file

@ -19,9 +19,7 @@ namespace sa2
~SDLImGuiFrame() override;
void UpdateTexture() override;
void RenderPresent() override;
void VideoPresentScreen() override;
void ResetSpeed() override;
protected:
@ -31,6 +29,7 @@ namespace sa2
private:
void UpdateTexture();
void ClearBackground();
void DrawAppleVideo();

View file

@ -235,6 +235,12 @@ namespace sa2
ImGui::Separator();
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::Checkbox("Full speed", &g_bFullSpeed);
ImGui::PopItemFlag();
ImGui::Separator();
if (ImGui::Button("Restart"))
{
frame->Restart();
@ -1096,7 +1102,7 @@ namespace sa2
if (ImGui::Button("Step"))
{
frame->ChangeMode(MODE_DEBUG);
frame->Execute(0);
frame->SingleStep();
}
ImGui::SameLine();

View file

@ -56,17 +56,6 @@ namespace
common2::Timer * timer;
};
void setGLSwapInterval(const int interval)
{
const int current = SDL_GL_GetSwapInterval();
// in QEMU with GL_RENDERER: llvmpipe (LLVM 12.0.0, 256 bits)
// SDL_GL_SetSwapInterval() always fails
if (interval != current && SDL_GL_SetSwapInterval(interval))
{
throw std::runtime_error(std::string("SDL_GL_SetSwapInterval: ") + SDL_GetError());
}
}
}
void run_sdl(int argc, const char * argv [])
@ -116,11 +105,10 @@ void run_sdl(int argc, const char * argv [])
{
// we need to switch off vsync, otherwise FPS is limited to 60
// and it will take longer to run
setGLSwapInterval(0);
sa2::SDLFrame::setGLSwapInterval(0);
const auto redraw = [&frame]{
frame->UpdateTexture();
frame->RenderPresent();
frame->VideoPresentScreen();
};
const auto refresh = [redraw, &video]{
@ -133,10 +121,7 @@ void run_sdl(int argc, const char * argv [])
}
else
{
setGLSwapInterval(options.glSwapInterval);
common2::Timer global;
common2::Timer updateTextureTimer;
common2::Timer refreshScreenTimer;
common2::Timer cpuTimer;
common2::Timer eventTimer;
@ -164,14 +149,10 @@ void run_sdl(int argc, const char * argv [])
frame->ExecuteOneFrame(oneFrame);
cpuTimer.toc();
updateTextureTimer.tic();
frame->UpdateTexture();
updateTextureTimer.toc();
if (!options.headless)
{
refreshScreenTimer.tic();
frame->RenderPresent();
frame->VideoPresentScreen();
refreshScreenTimer.toc();
}
frameTimer.toc();
@ -182,7 +163,6 @@ void run_sdl(int argc, const char * argv [])
std::cerr << "Global: " << global << std::endl;
std::cerr << "Frame: " << frameTimer << std::endl;
std::cerr << "Screen: " << refreshScreenTimer << std::endl;
std::cerr << "Texture: " << updateTextureTimer << std::endl;
std::cerr << "Events: " << eventTimer << std::endl;
std::cerr << "CPU: " << cpuTimer << std::endl;

View file

@ -49,13 +49,9 @@ namespace sa2
myPitch = width * sizeof(bgra_t);
}
void SDLRendererFrame::UpdateTexture()
void SDLRendererFrame::VideoPresentScreen()
{
SDL_UpdateTexture(myTexture.get(), nullptr, myFramebuffer.data(), myPitch);
}
void SDLRendererFrame::RenderPresent()
{
SDL_RenderCopyEx(myRenderer.get(), myTexture.get(), &myRect, nullptr, 0.0, nullptr, SDL_FLIP_VERTICAL);
SDL_RenderPresent(myRenderer.get());
}

View file

@ -15,8 +15,7 @@ namespace sa2
public:
SDLRendererFrame(const common2::EmulatorOptions & options);
void UpdateTexture() override;
void RenderPresent() override;
void VideoPresentScreen() override;
protected:
void GetRelativeMousePosition(const SDL_MouseMotionEvent & motion, double & x, double & y) const override;

View file

@ -32,11 +32,6 @@
namespace
{
bool canDoFullSpeed()
{
return GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !MB_IsActive();
}
void processAppleKey(const SDL_KeyboardEvent & key, const bool forceCapsLock)
{
// using keycode (or scan code) one takes a physical view of the keyboard
@ -130,19 +125,33 @@ namespace sa2
{
SDLFrame::SDLFrame(const common2::EmulatorOptions & options)
: myForceCapsLock(true)
: myTargetGLSwap(options.glSwapInterval)
, myForceCapsLock(true)
, myMultiplier(1)
, myFullscreen(false)
, myDragAndDropSlot(SLOT6)
, myDragAndDropDrive(DRIVE_1)
, myScrollLockFullSpeed(false)
, mySpeed(options.fixedSpeed)
{
}
void SDLFrame::setGLSwapInterval(const int interval)
{
const int current = SDL_GL_GetSwapInterval();
// in QEMU with GL_RENDERER: llvmpipe (LLVM 12.0.0, 256 bits)
// SDL_GL_SetSwapInterval() always fails
if (interval != current && SDL_GL_SetSwapInterval(interval))
{
throw std::runtime_error(std::string("SDL_GL_SetSwapInterval: ") + SDL_GetError());
}
}
void SDLFrame::Initialize()
{
CommonFrame::Initialize();
mySpeed.reset();
setGLSwapInterval(myTargetGLSwap);
}
void SDLFrame::FrameRefreshStatus(int drawflags)
@ -164,12 +173,6 @@ namespace sa2
}
}
void SDLFrame::VideoPresentScreen()
{
UpdateTexture();
RenderPresent();
}
const std::shared_ptr<SDL_Window> & SDLFrame::GetWindow() const
{
return myWindow;
@ -497,6 +500,11 @@ namespace sa2
}
break;
}
case SDLK_SCROLLLOCK:
{
myScrollLockFullSpeed = !myScrollLockFullSpeed;
break;
}
}
}
@ -558,44 +566,35 @@ namespace sa2
const DWORD executedCycles = CpuExecute(thisCyclesToExecute, bVideoUpdate);
totalCyclesExecuted += executedCycles;
g_dwCyclesThisFrame = (g_dwCyclesThisFrame + executedCycles) % dwClksPerFrame;
GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedCycles);
MB_PeriodicUpdate(executedCycles);
SpkrUpdate(executedCycles);
g_dwCyclesThisFrame += executedCycles;
if (g_dwCyclesThisFrame >= dwClksPerFrame)
{
g_dwCyclesThisFrame -= dwClksPerFrame;
if (g_bFullSpeed)
{
NTSC_VideoClockResync(g_dwCyclesThisFrame);
GetVideo().VideoRefreshBuffer(GetVideo().GetVideoMode(), true);
}
}
} while (totalCyclesExecuted < cyclesToExecute);
}
void SDLFrame::ExecuteInRunningMode(const size_t msNextFrame)
{
// 1 frame at normal speed
const uint64_t cyclesToExecute = mySpeed.getCyclesTillNext(msNextFrame * 1000);
SetFullSpeed(CanDoFullSpeed());
const uint64_t cyclesToExecute = mySpeed.getCyclesTillNext(msNextFrame * 1000); // this checks g_bFullSpeed
Execute(cyclesToExecute);
// up to 5x more as maximum speed
const int maximumFrames = 5;
const uint64_t cyclesToExecutePerFrame = mySpeed.getCyclesAtFixedSpeed(msNextFrame * 1000);
int count = maximumFrames;
while ((g_bFullSpeed = (count && canDoFullSpeed())))
{
Execute(cyclesToExecutePerFrame);
--count;
}
if (count < maximumFrames)
{
// we have run something in full speed
// Redraw and Reset
VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame);
ResetSpeed();
}
}
void SDLFrame::ExecuteInDebugMode(const size_t msNextFrame)
{
// In AppleWin this is called without a timer for just one iteration
// because we run a "frame" at a time, we need a bit of ingenuity
const uint64_t cyclesToExecute = mySpeed.getCyclesTillNext(msNextFrame * 1000);
const uint64_t cyclesToExecute = mySpeed.getCyclesAtFixedSpeed(msNextFrame * 1000);
const uint64_t target = g_nCumulativeCycles + cyclesToExecute;
while (g_nAppMode == MODE_STEPPING && g_nCumulativeCycles < target)
@ -664,9 +663,44 @@ namespace sa2
myDragAndDropDrive = drive;
}
void SDLFrame::SetFullSpeed(const bool value)
{
if (g_bFullSpeed != value)
{
if (value)
{
// entering full speed
MB_Mute();
setGLSwapInterval(0);
}
else
{
// leaving full speed
MB_Unmute();
setGLSwapInterval(myTargetGLSwap);
mySpeed.reset();
}
g_bFullSpeed = value;
}
}
bool SDLFrame::CanDoFullSpeed()
{
return myScrollLockFullSpeed ||
(g_dwSpeed == SPEED_MAX) ||
(GetCardMgr().GetDisk2CardMgr().IsConditionForFullSpeed() && !Spkr_IsActive() && !MB_IsActive()) ||
IsDebugSteppingAtFullSpeed();
}
void SDLFrame::SingleStep()
{
SetFullSpeed(CanDoFullSpeed());
Execute(0);
}
}
void SingleStep(bool /* bReinit */)
{
dynamic_cast<sa2::SDLFrame &>(GetFrame()).Execute(0);
dynamic_cast<sa2::SDLFrame &>(GetFrame()).SingleStep();
}

View file

@ -20,26 +20,24 @@ namespace sa2
void Initialize() override;
void VideoPresentScreen() override;
void FrameRefreshStatus(int drawflags) override;
int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) override;
void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits) override;
void ProcessEvents(bool &quit);
void Execute(const DWORD uCycles);
void ExecuteOneFrame(const size_t msNextFrame);
void ChangeMode(const AppMode_e mode);
void SingleStep();
virtual void ResetSpeed();
virtual void UpdateTexture() = 0;
virtual void RenderPresent() = 0;
const std::shared_ptr<SDL_Window> & GetWindow() const;
void getDragDropSlotAndDrive(size_t & slot, size_t & drive) const;
void setDragDropSlotAndDrive(const size_t slot, const size_t drive);
static void setGLSwapInterval(const int interval);
protected:
void SetApplicationIcon();
@ -55,11 +53,14 @@ namespace sa2
void ExecuteInRunningMode(const size_t msNextFrame);
void ExecuteInDebugMode(const size_t msNextFrame);
void Execute(const DWORD uCycles);
void SetFullSpeed(const bool value);
bool CanDoFullSpeed();
static double GetRelativePosition(const int value, const int width);
std::shared_ptr<SDL_Window> myWindow;
int myTargetGLSwap;
bool myForceCapsLock;
int myMultiplier;
bool myFullscreen;
@ -67,7 +68,11 @@ namespace sa2
size_t myDragAndDropSlot;
size_t myDragAndDropDrive;
bool myScrollLockFullSpeed;
common2::Speed mySpeed;
std::shared_ptr<SDL_Window> myWindow;
};
}