call sdl and wx from main thread

This commit is contained in:
Christopher A. Mosher 2022-12-06 13:30:35 -05:00
parent 3d4637a939
commit fc7806d3c9
5 changed files with 176 additions and 184 deletions

View File

@ -39,7 +39,6 @@
#include <boost/date_time/posix_time/posix_time.hpp>
#include <wx/debugrpt.h>
#include <iostream>
#include <thread>
#include <string>
#include <memory>
#include <algorithm>
@ -53,13 +52,37 @@ wxIMPLEMENT_APP_NO_MAIN(E2wxApp);
#ifndef PROJECT_VERSION
#define PROJECT_VERSION 0.0.1
#endif
std::promise<void> E2wxApp::barrier_to_init;
#ifndef PROJECT_VENDOR
#define PROJECT_VENDOR nu.mine.mosher
#endif
#ifndef PROJECT_NAME
#define PROJECT_NAME Epple-II
#endif
E2wxApp::E2wxApp() : id("nu.mine.mosher.epple2"), version(wxSTRINGIZE_T(PROJECT_VERSION)) {
EmuTimer::EmuTimer(Emulator *e) : wxTimer(), emu(e) {
}
EmuTimer::~EmuTimer() {
}
void EmuTimer::begin() {
this->Start(50); // TODO: EXPECTED_MS from Emulator
}
void EmuTimer::Notify() {
this->emu->tick50ms();
}
E2wxApp::E2wxApp() :
id(wxSTRINGIZE_T(PROJECT_VENDOR) wxT(".") wxSTRINGIZE_T(PROJECT_NAME)),
version(wxSTRINGIZE_T(PROJECT_VERSION)) {
}
E2wxApp::~E2wxApp() {
@ -69,11 +92,6 @@ E2wxApp::~E2wxApp() {
static std::filesystem::path dirCache() {
return std::filesystem::path(wxStandardPaths::Get().GetUserDir(wxStandardPaths::Dir_Cache).t_str());
}
@ -107,6 +125,8 @@ bool E2wxApp::OnInit() {
#endif
#endif
wxStandardPaths& stdpaths = wxStandardPaths::Get();
//stdpaths.SetInstallPrefix(".");
stdpaths.SetFileLayout(wxStandardPaths::FileLayout_XDG);
@ -117,16 +137,15 @@ bool E2wxApp::OnInit() {
this->confdir = dirConfig() / std::filesystem::path(GetID()+".d");
this->confdir = dirConfig() / std::filesystem::path((GetID()+wxT(".d")).t_str());
std::filesystem::create_directories(this->confdir);
BOOST_LOG_TRIVIAL(info) << "Configuration directory path: " << this->confdir;
this->conffile = dirConfig() / std::filesystem::path(GetID());
this->conffile = dirConfig() / std::filesystem::path(GetID().t_str());
BOOST_LOG_TRIVIAL(info) << "Configuration file path: " << this->conffile;
wxConfigBase::Set(new wxFileConfig("", "", GetID()));
this->docsdir = dirDocuments() / std::filesystem::path(GetID());
this->docsdir = dirDocuments() / std::filesystem::path(GetID().t_str());
BOOST_LOG_TRIVIAL(info) << "User document directory path: " << this->docsdir;
const std::filesystem::path exe = std::filesystem::path(stdpaths.GetExecutablePath().t_str());
@ -156,38 +175,33 @@ bool E2wxApp::OnInit() {
frame->Show();
barrier_to_init.set_value();
this->emu = new Emulator();
Config cfg((const std::string)this->arg_configfile.c_str());
this->emu->config(cfg);
this->emu->init();
this->emu_timer = new EmuTimer(this->emu);
this->emu_timer->begin();
return true;
}
static int run(const std::string config_file) {
GUI gui;
std::unique_ptr<Emulator> emu(new Emulator());
Config cfg(config_file);
emu->config(cfg);
emu->init();
return emu->run();
}
//void E2wxApp::StartSdlEpple2() {
// std::cout << "starting sdl thread..." << std::endl;
// this->thread_sdl = new std::thread(run, this->arg_configfile);
// std::cout << "started sdl thread." << std::endl;
//}
int E2wxApp::OnExit() {
// std::cout << "stopping sdl thread..." << std::endl;
GUI::queueQuit();
// this->thread_sdl->join();
// std::cout << "exiting wx application..." << std::endl;
if (this->emu_timer) {
delete this->emu_timer;
}
if (this->emu) {
delete this->emu;
}
return 0;
}
void E2wxApp::OnFatalException() {
wxDebugReport report;
report.AddAll();
@ -198,33 +212,36 @@ void E2wxApp::OnFatalException() {
}
}
//static const wxCmdLineEntryDesc cmdLineDesc[] =
//{
// { wxCMD_LINE_PARAM, NULL, NULL, "config file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
// wxCMD_LINE_DESC_END
//};
//
//void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) {
// wxApp::OnInitCmdLine(parser);
// parser.SetDesc(cmdLineDesc);
//}
//
//bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) {
// if (!wxApp::OnCmdLineParsed(parser)) {
// return false;
// }
//
// const int n = parser.GetParamCount();
//
// if (n <= 0) {
// std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl;
// } else {
// this->arg_configfile = parser.GetParam(0);
// std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl;
// }
//
// return true;
//}
static const wxCmdLineEntryDesc cmdLineDesc[] =
{
{ wxCMD_LINE_PARAM, NULL, NULL, "config-file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
wxCMD_LINE_DESC_END
};
void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) {
wxApp::OnInitCmdLine(parser);
parser.SetDesc(cmdLineDesc);
}
bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) {
if (!wxApp::OnCmdLineParsed(parser)) {
return false;
}
const int n = parser.GetParamCount();
if (n <= 0) {
std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl;
} else {
this->arg_configfile = parser.GetParam(0);
std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl;
}
return true;
}
const std::filesystem::path E2wxApp::GetLogFile() const {
@ -235,7 +252,7 @@ const std::filesystem::path E2wxApp::GetResDir() const {
return this->resdir;
}
const std::string E2wxApp::GetID() const {
const wxString E2wxApp::GetID() const {
return this->id;
}
@ -260,8 +277,8 @@ const std::filesystem::path E2wxApp::GetDocumentsDir() const {
const std::filesystem::path E2wxApp::BuildLogFilePath() const {
std::filesystem::path logfile =
dirCache() /
std::filesystem::path(GetID()) /
std::filesystem::path("log");
std::filesystem::path(GetID().t_str()) /
std::filesystem::path(wxT("log"));
std::filesystem::create_directories(logfile);
logfile = std::filesystem::canonical(logfile);

View File

@ -21,33 +21,55 @@
#ifndef E2WXAPP_H
#define E2WXAPP_H
#include <wx/app.h>
#include <wx/cmdline.h>
#include <wx/timer.h>
#include <wx/string.h>
#include <thread>
#include <filesystem>
#include <string>
#include <future>
class Emulator;
class EmuTimer : public wxTimer {
Emulator *emu;
public:
EmuTimer(Emulator *e);
virtual ~EmuTimer();
void Notify() override;
void begin();
};
class E2wxApp : public wxApp {
const std::string id;
const wxString id;
const wxString version;
std::filesystem::path logfile;
std::filesystem::path resdir;
std::filesystem::path conffile;
std::filesystem::path confdir;
std::filesystem::path docsdir;
wxString arg_configfile;
EmuTimer *emu_timer;
Emulator *emu;
const std::filesystem::path BuildLogFilePath() const;
void InitBoostLog();
public:
static std::promise<void> barrier_to_init;
E2wxApp();
virtual ~E2wxApp();
const std::string GetID() const;
const wxString GetID() const;
const wxString GetVersion() const;
const std::filesystem::path GetLogFile() const;
const std::filesystem::path GetResDir() const;
@ -58,10 +80,12 @@ public:
virtual bool OnInit() override;
virtual int OnExit() override;
virtual void OnFatalException() override;
// virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
// virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
};
wxDECLARE_APP(E2wxApp);
#endif /* E2WXAPP_H */

View File

@ -32,6 +32,8 @@ timable(0), // No ticked object (NULL pointer)
quit(false),
repeat(false),
keysDown(0),
skip(0),
prev_ms(SDL_GetTicks()),
command(false),
pendingCommandExit(false) {
}
@ -162,49 +164,11 @@ void Emulator::handleAnyPendingEvents() {
// The core of this Apple
int Emulator::run() {
int skip = 0;
Uint32 prev_ms = SDL_GetTicks();
// While the user still wants to run this emulation...
while (!this->quit) {
// (Obligatory protection against NULL object pointer)
if (this->timable) {
this->timable->tick();
handleRepeatKey();
}
// People who have too many press releases should be referred to as
// keyboards
if (CHECK_EVERY_CYCLE <= ++skip) {
// ...then it's time to drain away any piled-up user interaction
// events that SDL has stored up for us
// Reload the skip quantity
skip = 0;
handleAnyPendingEvents();
// If we're trying to run as slow as a real Apple ][...
if (!this->fhyper.isHyper()) {
const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - prev_ms);
if (0 < delta_ms && delta_ms <= EXPECTED_MS) {
SDL_Delay(delta_ms);
}
}
// Display the current estimate of the emulator's actual speed
// performance
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - prev_ms));
prev_ms = SDL_GetTicks();
}
tick();
}
return 0;
}
@ -212,6 +176,54 @@ int Emulator::run() {
void Emulator::tick() {
if (this->timable) {
this->timable->tick(); // this runs the emulator!
handleRepeatKey();
}
// People who have too many press releases should be referred to as
// keyboards
if (CHECK_EVERY_CYCLE <= ++this->skip) {
// ...then it's time to drain away any piled-up user interaction
// events that SDL has stored up for us
// Reload the skip quantity
this->skip = 0;
handleAnyPendingEvents();
// If we're trying to run as slow as a real Apple ][...
if (!this->fhyper.isHyper()) {
const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - this->prev_ms);
if (0 < delta_ms && delta_ms <= EXPECTED_MS) {
SDL_Delay(delta_ms);
}
}
// Display the current estimate of the emulator's actual speed
// performance
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms));
this->prev_ms = SDL_GetTicks();
}
}
void Emulator::tick50ms() {
if (this->timable) {
for (int i = 0; i < CHECK_EVERY_CYCLE; ++i) {
this->timable->tick(); // this runs the emulator!
handleRepeatKey();
}
}
handleAnyPendingEvents();
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms));
this->prev_ms = SDL_GetTicks();
// TODO: how to check this->quit ?
}

View File

@ -52,10 +52,14 @@ class Emulator
int keysDown;
int rept;
unsigned char lastKeyDown;
int skip;
Uint32 prev_ms;
bool command;
bool pendingCommandExit;
std::string cmdline;
void tick();
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
void cmdKey(const SDL_KeyboardEvent& keyEvent);
@ -80,6 +84,7 @@ public:
void quitIfSafe();
virtual int run();
void tick50ms();
};
#endif

View File

@ -1,6 +1,7 @@
/*
epple2
Copyright (C) 2008, 2022 by Christopher A. Mosher <cmosher01@gmail.com>
Copyright (C) 2008, 2022 by Christopher A. Mosher, <cmosher01@gmail.com> https://mosher.mine.nu https://github.com/cmosher01
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,81 +17,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "e2const.h"
#include "emulator.h"
#include "configep2.h"
#include "gui.h"
#include "e2const.h"
#include "E2wxApp.h"
#include <wx/app.h>
#include <thread>
#include <future>
#include <chrono>
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <cstdio>
#include <cstddef>
using namespace std::chrono_literals;
static std::string parse_args(int argc, char* argv[]) {
if (argc > 2) {
throw std::runtime_error("usage: epple2 [config-file]" );
}
if (argc <= 1) {
return std::string();
}
return std::string(argv[1]);
}
static int fake_argc(1);
static char fake_prog[] = "epple2";
static char *fake_argv[] { fake_prog };
static int runWx() {
std::cout << "starting wx..." << std::endl;
return wxEntry(fake_argc, fake_argv);
}
static int runSdl(const std::string config_file) {
GUI gui;
std::future<void> barrier_to_app_init = E2wxApp::barrier_to_init.get_future();
std::thread thread_wx(runWx);
std::cout << "wait for wx init" << std::endl;
const std::future_status fut = barrier_to_app_init.wait_for(10s);
if (fut == std::future_status::timeout) {
std::cerr << "timed-out waiting for wx to finish initializing" << std::endl;
return 1;
}
std::cout << "wx init finished" << std::endl;
std::unique_ptr<Emulator> emu(new Emulator());
Config cfg(config_file);
emu->config(cfg);
emu->init();
const int ret = emu->run();
if (wxApp::GetInstance() != nullptr) {
wxApp::GetInstance()->ExitMainLoop();
}
thread_wx.join();
return ret;
}
#ifdef __cplusplus
@ -106,9 +42,7 @@ int main(int argc, char *argv[]) {
throw std::runtime_error("bad constant in e2const.h" );
}
const std::string config_file = parse_args(argc, argv);
GUI gui;
const int ret = runSdl(config_file);
return ret;
return wxEntry(argc, argv);
}