mirror of https://github.com/snes9xgit/snes9x.git
Threading.
This commit is contained in:
parent
177a802186
commit
a438d3fa42
|
@ -1 +1 @@
|
||||||
Subproject commit 3ebb72cc7429f0ab8218104dc3687c659c0f364d
|
Subproject commit 9c7fd1a33e5cecbe465e1cd70170167d5e40d398
|
|
@ -26,6 +26,7 @@ EmuApplication::~EmuApplication()
|
||||||
|
|
||||||
void EmuApplication::restartAudio()
|
void EmuApplication::restartAudio()
|
||||||
{
|
{
|
||||||
|
suspendThread();
|
||||||
sound_driver.reset();
|
sound_driver.reset();
|
||||||
core->sound_output_function = nullptr;
|
core->sound_output_function = nullptr;
|
||||||
|
|
||||||
|
@ -55,6 +56,8 @@ void EmuApplication::restartAudio()
|
||||||
core->sound_output_function = [&](int16_t *data, int samples) {
|
core->sound_output_function = [&](int16_t *data, int samples) {
|
||||||
writeSamples(data, samples);
|
writeSamples(data, samples);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
unsuspendThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SOUND_BUFFER_WINDOW
|
#ifdef SOUND_BUFFER_WINDOW
|
||||||
|
@ -124,13 +127,14 @@ void EmuApplication::writeSamples(int16_t *data, int samples)
|
||||||
|
|
||||||
void EmuApplication::startGame()
|
void EmuApplication::startGame()
|
||||||
{
|
{
|
||||||
|
suspendThread();
|
||||||
if (!sound_driver)
|
if (!sound_driver)
|
||||||
restartAudio();
|
restartAudio();
|
||||||
|
|
||||||
core->screen_output_function = [&](uint16_t *data, int width, int height, int stride_bytes, double frame_rate) {
|
core->screen_output_function = [&](uint16_t *data, int width, int height, int stride_bytes, double frame_rate) {
|
||||||
if (window->canvas)
|
if (window->canvas)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(window.get(), "output", Qt::ConnectionType::QueuedConnection,
|
QMetaObject::invokeMethod(window.get(), "output", Qt::ConnectionType::DirectConnection,
|
||||||
Q_ARG(uint8_t *, (uint8_t *)data),
|
Q_ARG(uint8_t *, (uint8_t *)data),
|
||||||
Q_ARG(int, width),
|
Q_ARG(int, width),
|
||||||
Q_ARG(int, height),
|
Q_ARG(int, height),
|
||||||
|
@ -143,7 +147,12 @@ void EmuApplication::startGame()
|
||||||
updateSettings();
|
updateSettings();
|
||||||
updateBindings();
|
updateBindings();
|
||||||
|
|
||||||
startIdleLoop();
|
emu_thread->setMainLoop([&] {
|
||||||
|
mainLoop();
|
||||||
|
});
|
||||||
|
|
||||||
|
unsuspendThread();
|
||||||
|
unpause();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuApplication::isPaused()
|
bool EmuApplication::isPaused()
|
||||||
|
@ -151,21 +160,61 @@ bool EmuApplication::isPaused()
|
||||||
return (pause_count != 0);
|
return (pause_count != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuApplication::suspendThread()
|
||||||
|
{
|
||||||
|
suspend_count++;
|
||||||
|
|
||||||
|
if (!emu_thread)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (suspend_count > 0)
|
||||||
|
{
|
||||||
|
printf("Suspend %d\n", suspend_count);
|
||||||
|
emu_thread->runOnThread([&] { emu_thread->setStatusBits(EmuThread::eSuspended); });
|
||||||
|
emu_thread->waitForStatusBit(EmuThread::eSuspended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuApplication::unsuspendThread()
|
||||||
|
{
|
||||||
|
suspend_count--;
|
||||||
|
assert(suspend_count >= 0);
|
||||||
|
|
||||||
|
if (!emu_thread)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("Un Suspend %d\n", suspend_count);
|
||||||
|
|
||||||
|
if (suspend_count == 0)
|
||||||
|
{
|
||||||
|
emu_thread->runOnThread([&] { emu_thread->unsetStatusBits(EmuThread::eSuspended); });
|
||||||
|
emu_thread->waitForStatusBitCleared(EmuThread::eSuspended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EmuApplication::pause()
|
void EmuApplication::pause()
|
||||||
{
|
{
|
||||||
pause_count++;
|
pause_count++;
|
||||||
if (pause_count > 0)
|
if (pause_count > 0)
|
||||||
{
|
{
|
||||||
|
if (emu_thread)
|
||||||
|
emu_thread->pause();
|
||||||
core->setPaused(true);
|
core->setPaused(true);
|
||||||
if (sound_driver)
|
if (sound_driver)
|
||||||
sound_driver->stop();
|
sound_driver->stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::stopIdleLoop()
|
void EmuApplication::stopThread()
|
||||||
{
|
{
|
||||||
idle_loop->stop();
|
if (!emu_thread)
|
||||||
pause_count = 0;
|
return;
|
||||||
|
|
||||||
|
emu_thread->setStatusBits(EmuThread::eQuit);
|
||||||
|
while (!emu_thread->isFinished())
|
||||||
|
{
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::unpause()
|
void EmuApplication::unpause()
|
||||||
|
@ -179,47 +228,42 @@ void EmuApplication::unpause()
|
||||||
core->setPaused(false);
|
core->setPaused(false);
|
||||||
if (core->active && sound_driver)
|
if (core->active && sound_driver)
|
||||||
sound_driver->start();
|
sound_driver->start();
|
||||||
|
if (emu_thread)
|
||||||
|
emu_thread->unpause();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::startIdleLoop()
|
void EmuApplication::startThread()
|
||||||
{
|
{
|
||||||
if (!idle_loop)
|
if (!emu_thread)
|
||||||
{
|
{
|
||||||
idle_loop = std::make_unique<QTimer>();
|
emu_thread = std::make_unique<EmuThread>(QThread::currentThread());
|
||||||
idle_loop->setTimerType(Qt::TimerType::PreciseTimer);
|
emu_thread->start();
|
||||||
idle_loop->setInterval(0);
|
emu_thread->waitForStatusBit(EmuThread::ePaused);
|
||||||
idle_loop->setSingleShot(false);
|
emu_thread->moveToThread(emu_thread.get());
|
||||||
idle_loop->callOnTimeout([&]{ idleLoop(); });
|
|
||||||
pause_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
idle_loop->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void EmuApplication::idleLoop()
|
|
||||||
{
|
|
||||||
if (core->active && pause_count == 0)
|
|
||||||
{
|
|
||||||
idle_loop->setInterval(0);
|
|
||||||
pollJoysticks();
|
|
||||||
bool muted = config->mute_audio || (config->mute_audio_during_alternate_speed && core->isAbnormalSpeed());
|
|
||||||
core->mute(muted);
|
|
||||||
core->mainLoop();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pollJoysticks();
|
|
||||||
idle_loop->setInterval(32);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EmuApplication::openFile(std::string filename)
|
bool EmuApplication::openFile(std::string filename)
|
||||||
{
|
{
|
||||||
|
suspendThread();
|
||||||
auto result = core->openFile(filename);
|
auto result = core->openFile(filename);
|
||||||
|
unsuspendThread();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuApplication::mainLoop()
|
||||||
|
{
|
||||||
|
if (!core->active)
|
||||||
|
{
|
||||||
|
std::this_thread::yield();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Here\n");
|
||||||
|
core->mainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
void EmuApplication::reportBinding(EmuBinding b, bool active)
|
void EmuApplication::reportBinding(EmuBinding b, bool active)
|
||||||
{
|
{
|
||||||
if (binding_callback && active)
|
if (binding_callback && active)
|
||||||
|
@ -238,7 +282,7 @@ void EmuApplication::reportBinding(EmuBinding b, bool active)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
core->reportBinding(b, active);
|
emu_thread->runOnThread([&, b, active] { core->reportBinding(b, active); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::updateBindings()
|
void EmuApplication::updateBindings()
|
||||||
|
@ -273,7 +317,9 @@ void EmuApplication::updateBindings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspendThread();
|
||||||
core->updateBindings(config.get());
|
core->updateBindings(config.get());
|
||||||
|
unsuspendThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::handleBinding(std::string name, bool pressed)
|
void EmuApplication::handleBinding(std::string name, bool pressed)
|
||||||
|
@ -296,14 +342,18 @@ void EmuApplication::handleBinding(std::string name, bool pressed)
|
||||||
save_slot++;
|
save_slot++;
|
||||||
if (save_slot > 999)
|
if (save_slot > 999)
|
||||||
save_slot = 0;
|
save_slot = 0;
|
||||||
core->setMessage("Current slot: " + std::to_string(save_slot));
|
emu_thread->runOnThread([&] {
|
||||||
|
core->setMessage("Current slot: " + std::to_string(save_slot));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (name == "DecreaseSlot")
|
else if (name == "DecreaseSlot")
|
||||||
{
|
{
|
||||||
save_slot--;
|
save_slot--;
|
||||||
if (save_slot < 0)
|
if (save_slot < 0)
|
||||||
save_slot = 999;
|
save_slot = 999;
|
||||||
core->setMessage("Current slot: " + std::to_string(save_slot));
|
emu_thread->runOnThread([&] {
|
||||||
|
core->setMessage("Current slot: " + std::to_string(save_slot));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else if (name == "SaveState")
|
else if (name == "SaveState")
|
||||||
{
|
{
|
||||||
|
@ -349,7 +399,9 @@ void EmuApplication::updateSettings()
|
||||||
config->input_rate /= 4;
|
config->input_rate /= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
core->updateSettings(config.get());
|
emu_thread->runOnThread([&] {
|
||||||
|
core->updateSettings(config.get());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::pollJoysticks()
|
void EmuApplication::pollJoysticks()
|
||||||
|
@ -401,39 +453,63 @@ void EmuApplication::pollJoysticks()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmuApplication::startInputTimer()
|
||||||
|
{
|
||||||
|
poll_input_timer = std::make_unique<QTimer>();
|
||||||
|
poll_input_timer->setTimerType(Qt::TimerType::PreciseTimer);
|
||||||
|
poll_input_timer->setInterval(4);
|
||||||
|
poll_input_timer->setSingleShot(false);
|
||||||
|
poll_input_timer->callOnTimeout([&] { pollJoysticks(); });
|
||||||
|
poll_input_timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
void EmuApplication::loadState(int slot)
|
void EmuApplication::loadState(int slot)
|
||||||
{
|
{
|
||||||
core->loadState(slot);
|
emu_thread->runOnThread([&] {
|
||||||
|
core->loadState(slot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::loadState(std::string filename)
|
void EmuApplication::loadState(std::string filename)
|
||||||
{
|
{
|
||||||
core->loadState(filename);
|
emu_thread->runOnThread([&] {
|
||||||
|
core->loadState(filename);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::saveState(int slot)
|
void EmuApplication::saveState(int slot)
|
||||||
{
|
{
|
||||||
core->saveState(slot);
|
emu_thread->runOnThread([&] {
|
||||||
|
core->saveState(slot);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::saveState(std::string filename)
|
void EmuApplication::saveState(std::string filename)
|
||||||
{
|
{
|
||||||
core->saveState(filename);
|
emu_thread->runOnThread([&] {
|
||||||
|
core->saveState(filename);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::reset()
|
void EmuApplication::reset()
|
||||||
{
|
{
|
||||||
core->softReset();
|
emu_thread->runOnThread([&] {
|
||||||
|
core->softReset();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::powerCycle()
|
void EmuApplication::powerCycle()
|
||||||
{
|
{
|
||||||
core->reset();
|
emu_thread->runOnThread([&] {
|
||||||
|
core->reset();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuApplication::loadUndoState()
|
void EmuApplication::loadUndoState()
|
||||||
{
|
{
|
||||||
core->loadUndoState();
|
emu_thread->runOnThread([&] {
|
||||||
|
core->loadUndoState();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EmuApplication::getStateFolder()
|
std::string EmuApplication::getStateFolder()
|
||||||
|
@ -444,4 +520,110 @@ std::string EmuApplication::getStateFolder()
|
||||||
bool EmuApplication::isCoreActive()
|
bool EmuApplication::isCoreActive()
|
||||||
{
|
{
|
||||||
return core->active;
|
return core->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::runOnThread(std::function<void()> func)
|
||||||
|
{
|
||||||
|
if (QThread::currentThread() != this)
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(this, "runOnThread", Q_ARG(std::function<void()>, func));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmuThread::EmuThread(QThread *main_thread_)
|
||||||
|
: main_thread(main_thread_), QThread()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<std::function<void()>>("std::function<void()>");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::setStatusBits(int new_status)
|
||||||
|
{
|
||||||
|
std::unique_lock lock(status_mutex);
|
||||||
|
status |= new_status;
|
||||||
|
lock.unlock();
|
||||||
|
status_cond.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::unsetStatusBits(int new_status)
|
||||||
|
{
|
||||||
|
printf("Old: %08x, new: %08x\n", status, new_status);
|
||||||
|
std::unique_lock lock(status_mutex);
|
||||||
|
status &= ~new_status;
|
||||||
|
printf("Final: %08x\n", status);
|
||||||
|
lock.unlock();
|
||||||
|
status_cond.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::waitForStatusBit(int new_status)
|
||||||
|
{
|
||||||
|
if (status & new_status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
std::unique_lock lock(status_mutex);
|
||||||
|
status_cond.wait_for(lock, std::chrono::milliseconds(500));
|
||||||
|
if (status & new_status)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::waitForStatusBitCleared(int new_status)
|
||||||
|
{
|
||||||
|
if (!(status & new_status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
std::unique_lock lock(status_mutex);
|
||||||
|
status_cond.wait_for(lock, std::chrono::milliseconds(500));
|
||||||
|
if (!(status & new_status))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::pause()
|
||||||
|
{
|
||||||
|
runOnThread([&] { setStatusBits(ePaused); });
|
||||||
|
waitForStatusBit(ePaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::unpause()
|
||||||
|
{
|
||||||
|
runOnThread([&] { unsetStatusBits(ePaused); });
|
||||||
|
waitForStatusBitCleared(ePaused);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::run()
|
||||||
|
{
|
||||||
|
auto event_loop = new QEventLoop();
|
||||||
|
|
||||||
|
setStatusBits(ePaused);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
event_loop->processEvents();
|
||||||
|
|
||||||
|
if (status & eQuit)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status & (ePaused | eSuspended))
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(2ms);
|
||||||
|
printf("Paused: %08x\n", status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Loop\n");
|
||||||
|
if (main_loop)
|
||||||
|
main_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuThread::setMainLoop(std::function<void ()> loop)
|
||||||
|
{
|
||||||
|
main_loop = loop;
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
#include "EmuMainWindow.hpp"
|
#include "EmuMainWindow.hpp"
|
||||||
#include "EmuConfig.hpp"
|
#include "EmuConfig.hpp"
|
||||||
|
@ -8,6 +9,39 @@
|
||||||
#include "Snes9xController.hpp"
|
#include "Snes9xController.hpp"
|
||||||
#include "common/audio/s9x_sound_driver.hpp"
|
#include "common/audio/s9x_sound_driver.hpp"
|
||||||
|
|
||||||
|
struct EmuThread : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
EmuThread(QThread *main_thread);
|
||||||
|
QThread *main_thread;
|
||||||
|
void run() override;
|
||||||
|
void waitForStatusBit(int);
|
||||||
|
void waitForStatusBitCleared(int);
|
||||||
|
void setStatusBits(int);
|
||||||
|
void unsetStatusBits(int);
|
||||||
|
void pause();
|
||||||
|
void unpause();
|
||||||
|
void setMainLoop(std::function<void()> loop);
|
||||||
|
|
||||||
|
std::function<void()> main_loop = nullptr;
|
||||||
|
|
||||||
|
enum StatusBits
|
||||||
|
{
|
||||||
|
eDead = 0,
|
||||||
|
ePaused = 1,
|
||||||
|
eSuspended = 2,
|
||||||
|
eRunning = 4,
|
||||||
|
eQuit = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
int status = eDead;
|
||||||
|
std::mutex status_mutex;
|
||||||
|
std::condition_variable status_cond;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void runOnThread(std::function<void()> func);
|
||||||
|
};
|
||||||
|
|
||||||
struct EmuApplication
|
struct EmuApplication
|
||||||
{
|
{
|
||||||
|
@ -16,6 +50,7 @@ struct EmuApplication
|
||||||
std::unique_ptr<SDLInputManager> input_manager;
|
std::unique_ptr<SDLInputManager> input_manager;
|
||||||
std::unique_ptr<EmuMainWindow> window;
|
std::unique_ptr<EmuMainWindow> window;
|
||||||
std::unique_ptr<S9xSoundDriver> sound_driver;
|
std::unique_ptr<S9xSoundDriver> sound_driver;
|
||||||
|
std::unique_ptr<EmuThread> emu_thread;
|
||||||
Snes9xController *core;
|
Snes9xController *core;
|
||||||
|
|
||||||
EmuApplication();
|
EmuApplication();
|
||||||
|
@ -26,12 +61,16 @@ struct EmuApplication
|
||||||
void updateBindings();
|
void updateBindings();
|
||||||
bool isBound(EmuBinding b);
|
bool isBound(EmuBinding b);
|
||||||
void reportBinding(EmuBinding b, bool active);
|
void reportBinding(EmuBinding b, bool active);
|
||||||
|
void startInputTimer();
|
||||||
void pollJoysticks();
|
void pollJoysticks();
|
||||||
void restartAudio();
|
void restartAudio();
|
||||||
void writeSamples(int16_t *data, int samples);
|
void writeSamples(int16_t *data, int samples);
|
||||||
|
void mainLoop();
|
||||||
void pause();
|
void pause();
|
||||||
void reset();
|
void reset();
|
||||||
void powerCycle();
|
void powerCycle();
|
||||||
|
void suspendThread();
|
||||||
|
void unsuspendThread();
|
||||||
bool isPaused();
|
bool isPaused();
|
||||||
void unpause();
|
void unpause();
|
||||||
void loadState(int slot);
|
void loadState(int slot);
|
||||||
|
@ -41,9 +80,8 @@ struct EmuApplication
|
||||||
std::string getStateFolder();
|
std::string getStateFolder();
|
||||||
void loadUndoState();
|
void loadUndoState();
|
||||||
void startGame();
|
void startGame();
|
||||||
void startIdleLoop();
|
void startThread();
|
||||||
void stopIdleLoop();
|
void stopThread();
|
||||||
void idleLoop();
|
|
||||||
bool isCoreActive();
|
bool isCoreActive();
|
||||||
|
|
||||||
enum Handler
|
enum Handler
|
||||||
|
@ -52,9 +90,10 @@ struct EmuApplication
|
||||||
UI = 1
|
UI = 1
|
||||||
};
|
};
|
||||||
std::map<uint32_t, std::pair<std::string, Handler>> bindings;
|
std::map<uint32_t, std::pair<std::string, Handler>> bindings;
|
||||||
std::unique_ptr<QTimer> idle_loop;
|
std::unique_ptr<QTimer> poll_input_timer;
|
||||||
std::function<void(EmuBinding)> binding_callback = nullptr;
|
std::function<void(EmuBinding)> binding_callback = nullptr;
|
||||||
std::function<void()> joypads_changed_callback = nullptr;
|
std::function<void()> joypads_changed_callback = nullptr;
|
||||||
int save_slot = 0;
|
int save_slot = 0;
|
||||||
int pause_count = 0;
|
int pause_count = 0;
|
||||||
|
int suspend_count = 0;
|
||||||
};
|
};
|
|
@ -14,6 +14,7 @@ class EmuCanvas : public QWidget
|
||||||
virtual void draw() = 0;
|
virtual void draw() = 0;
|
||||||
void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate);
|
void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate);
|
||||||
void throttle();
|
void throttle();
|
||||||
|
void resizeEvent(QResizeEvent *event) override = 0;
|
||||||
|
|
||||||
virtual std::vector<std::string> getDeviceList()
|
virtual std::vector<std::string> getDeviceList()
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,4 +44,9 @@ void EmuCanvasQt::paintEvent(QPaintEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
paint.drawImage(dest, image, QRect(0, 0, output_data.width, output_data.height));
|
paint.drawImage(dest, image, QRect(0, 0, output_data.width, output_data.height));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmuCanvasQt::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
}
|
}
|
|
@ -15,6 +15,7 @@ class EmuCanvasQt : public EmuCanvas
|
||||||
virtual void draw() override;
|
virtual void draw() override;
|
||||||
|
|
||||||
void paintEvent(QPaintEvent *event) override;
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -109,8 +109,10 @@ void EmuMainWindow::createCanvas()
|
||||||
|
|
||||||
void EmuMainWindow::recreateCanvas()
|
void EmuMainWindow::recreateCanvas()
|
||||||
{
|
{
|
||||||
|
app->suspendThread();
|
||||||
destroyCanvas();
|
destroyCanvas();
|
||||||
createCanvas();
|
createCanvas();
|
||||||
|
app->unsuspendThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuMainWindow::setCoreActionsEnabled(bool enable)
|
void EmuMainWindow::setCoreActionsEnabled(bool enable)
|
||||||
|
@ -528,6 +530,15 @@ void EmuMainWindow::toggleFullscreen()
|
||||||
|
|
||||||
bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event)
|
bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
|
if (watched == canvas && event->type() == QEvent::Resize)
|
||||||
|
{
|
||||||
|
app->suspendThread();
|
||||||
|
canvas->resizeEvent((QResizeEvent *)event);
|
||||||
|
event->accept();
|
||||||
|
app->unsuspendThread();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease)
|
if (event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -26,12 +26,11 @@ int main(int argc, char *argv[])
|
||||||
emu.window->show();
|
emu.window->show();
|
||||||
|
|
||||||
emu.updateBindings();
|
emu.updateBindings();
|
||||||
emu.startIdleLoop();
|
emu.startInputTimer();
|
||||||
|
emu.startThread();
|
||||||
|
|
||||||
|
|
||||||
emu.qtapp->exec();
|
emu.qtapp->exec();
|
||||||
|
|
||||||
|
emu.stopThread();
|
||||||
emu.config->saveFile(EmuConfig::findConfigFile());
|
emu.config->saveFile(EmuConfig::findConfigFile());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue