mirror of https://github.com/snes9xgit/snes9x.git
Threading fixes.
This commit is contained in:
parent
a438d3fa42
commit
e42dd27cd1
|
@ -1 +1 @@
|
|||
Subproject commit 9c7fd1a33e5cecbe465e1cd70170167d5e40d398
|
||||
Subproject commit 3ebb72cc7429f0ab8218104dc3687c659c0f364d
|
|
@ -2,6 +2,7 @@
|
|||
#include "common/audio/s9x_sound_driver_sdl.hpp"
|
||||
#include "common/audio/s9x_sound_driver_cubeb.hpp"
|
||||
#include <qlabel.h>
|
||||
#include <qnamespace.h>
|
||||
#ifdef USE_PULSEAUDIO
|
||||
#include "common/audio/s9x_sound_driver_pulse.hpp"
|
||||
#endif
|
||||
|
@ -169,9 +170,7 @@ void EmuApplication::suspendThread()
|
|||
|
||||
if (suspend_count > 0)
|
||||
{
|
||||
printf("Suspend %d\n", suspend_count);
|
||||
emu_thread->runOnThread([&] { emu_thread->setStatusBits(EmuThread::eSuspended); });
|
||||
emu_thread->waitForStatusBit(EmuThread::eSuspended);
|
||||
emu_thread->runOnThread([&] { emu_thread->setStatusBits(EmuThread::eSuspended); }, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,12 +182,9 @@ void EmuApplication::unsuspendThread()
|
|||
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);
|
||||
emu_thread->runOnThread([&] { emu_thread->unsetStatusBits(EmuThread::eSuspended); }, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,7 +256,6 @@ void EmuApplication::mainLoop()
|
|||
return;
|
||||
}
|
||||
|
||||
printf("Here\n");
|
||||
core->mainLoop();
|
||||
}
|
||||
|
||||
|
@ -522,11 +517,15 @@ bool EmuApplication::isCoreActive()
|
|||
return core->active;
|
||||
}
|
||||
|
||||
void EmuThread::runOnThread(std::function<void()> func)
|
||||
void EmuThread::runOnThread(std::function<void()> func, bool blocking)
|
||||
{
|
||||
if (QThread::currentThread() != this)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "runOnThread", Q_ARG(std::function<void()>, func));
|
||||
QMetaObject::invokeMethod(this,
|
||||
"runOnThread",
|
||||
blocking ? Qt::BlockingQueuedConnection : Qt::QueuedConnection,
|
||||
Q_ARG(std::function<void()>, func),
|
||||
Q_ARG(bool, blocking));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -541,20 +540,12 @@ EmuThread::EmuThread(QThread *main_thread_)
|
|||
|
||||
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)
|
||||
|
@ -564,8 +555,7 @@ void EmuThread::waitForStatusBit(int new_status)
|
|||
|
||||
while (1)
|
||||
{
|
||||
std::unique_lock lock(status_mutex);
|
||||
status_cond.wait_for(lock, std::chrono::milliseconds(500));
|
||||
QThread::yieldCurrentThread();
|
||||
if (status & new_status)
|
||||
break;
|
||||
}
|
||||
|
@ -578,8 +568,7 @@ void EmuThread::waitForStatusBitCleared(int new_status)
|
|||
|
||||
while (1)
|
||||
{
|
||||
std::unique_lock lock(status_mutex);
|
||||
status_cond.wait_for(lock, std::chrono::milliseconds(500));
|
||||
QThread::yieldCurrentThread();
|
||||
if (!(status & new_status))
|
||||
break;
|
||||
}
|
||||
|
@ -587,14 +576,12 @@ void EmuThread::waitForStatusBitCleared(int new_status)
|
|||
|
||||
void EmuThread::pause()
|
||||
{
|
||||
runOnThread([&] { setStatusBits(ePaused); });
|
||||
waitForStatusBit(ePaused);
|
||||
runOnThread([&] { setStatusBits(ePaused); }, true);
|
||||
}
|
||||
|
||||
void EmuThread::unpause()
|
||||
{
|
||||
runOnThread([&] { unsetStatusBits(ePaused); });
|
||||
waitForStatusBitCleared(ePaused);
|
||||
runOnThread([&] { unsetStatusBits(ePaused); }, true);
|
||||
}
|
||||
|
||||
void EmuThread::run()
|
||||
|
@ -612,12 +599,10 @@ void EmuThread::run()
|
|||
|
||||
if (status & (ePaused | eSuspended))
|
||||
{
|
||||
std::this_thread::sleep_for(2ms);
|
||||
printf("Paused: %08x\n", status);
|
||||
QThread::usleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Loop\n");
|
||||
if (main_loop)
|
||||
main_loop();
|
||||
}
|
||||
|
|
|
@ -36,11 +36,9 @@ Q_OBJECT
|
|||
};
|
||||
|
||||
int status = eDead;
|
||||
std::mutex status_mutex;
|
||||
std::condition_variable status_cond;
|
||||
|
||||
public slots:
|
||||
void runOnThread(std::function<void()> func);
|
||||
void runOnThread(std::function<void()> func, bool blocking = false);
|
||||
};
|
||||
|
||||
struct EmuApplication
|
||||
|
|
|
@ -12,6 +12,8 @@ class EmuCanvas : public QWidget
|
|||
|
||||
virtual void deinit() = 0;
|
||||
virtual void draw() = 0;
|
||||
void paintEvent(QPaintEvent *) override = 0;
|
||||
virtual void createContext() {}
|
||||
void output(uint8_t *buffer, int width, int height, QImage::Format format, int bytes_per_line, double frame_rate);
|
||||
void throttle();
|
||||
void resizeEvent(QResizeEvent *event) override = 0;
|
||||
|
|
|
@ -57,11 +57,6 @@ EmuCanvasOpenGL::EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *ma
|
|||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
|
||||
createWinId();
|
||||
|
||||
auto timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
timer->callOnTimeout([&]{ createContext(); });
|
||||
timer->start();
|
||||
}
|
||||
|
||||
EmuCanvasOpenGL::~EmuCanvasOpenGL()
|
||||
|
@ -251,6 +246,7 @@ void EmuCanvasOpenGL::draw()
|
|||
return;
|
||||
|
||||
context->make_current();
|
||||
gladLoaderLoadGL();
|
||||
|
||||
uploadTexture();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
@ -298,7 +294,8 @@ void EmuCanvasOpenGL::resizeEvent(QResizeEvent *event)
|
|||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
if (!context) return;
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
auto g = parent->geometry();
|
||||
int s = devicePixelRatio();
|
||||
|
@ -308,6 +305,8 @@ void EmuCanvasOpenGL::resizeEvent(QResizeEvent *event)
|
|||
((WaylandEGLContext *)context.get())->resize({ g.x(), g.y(), g.width(), g.height(), s });
|
||||
else if (platform == "xcb")
|
||||
((GTKGLXContext *)context.get())->resize();
|
||||
#else
|
||||
((WGLContext *)context.get())->resize();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -324,6 +323,9 @@ void EmuCanvasOpenGL::paintEvent(QPaintEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
((WGLContext *)context.get())->resize();
|
||||
#endif
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
context->swap_buffers();
|
||||
|
|
|
@ -14,6 +14,7 @@ class EmuCanvasOpenGL : public EmuCanvas
|
|||
EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window);
|
||||
~EmuCanvasOpenGL();
|
||||
|
||||
void createContext() override;
|
||||
void deinit() override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
@ -26,7 +27,6 @@ class EmuCanvasOpenGL : public EmuCanvas
|
|||
|
||||
private:
|
||||
void resizeTexture(int width, int height);
|
||||
void createContext();
|
||||
void createStockShaders();
|
||||
void stockShaderDraw();
|
||||
void customShaderDraw();
|
||||
|
|
|
@ -25,11 +25,6 @@ EmuCanvasVulkan::EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *ma
|
|||
|
||||
createWinId();
|
||||
window = windowHandle();
|
||||
|
||||
auto timer = new QTimer(this);
|
||||
timer->setSingleShot(true);
|
||||
timer->callOnTimeout([&]{ createContext(); });
|
||||
timer->start();
|
||||
}
|
||||
|
||||
EmuCanvasVulkan::~EmuCanvasVulkan()
|
||||
|
|
|
@ -16,6 +16,7 @@ class EmuCanvasVulkan : public EmuCanvas
|
|||
EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window);
|
||||
~EmuCanvasVulkan();
|
||||
|
||||
void createContext();
|
||||
void deinit() override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
@ -37,7 +38,6 @@ class EmuCanvasVulkan : public EmuCanvas
|
|||
std::unique_ptr<Vulkan::ShaderChain> shader_chain;
|
||||
|
||||
private:
|
||||
void createContext();
|
||||
void tryLoadShader();
|
||||
std::string current_shader;
|
||||
QWindow *window = nullptr;
|
||||
|
|
|
@ -84,22 +84,40 @@ void EmuMainWindow::createCanvas()
|
|||
auto central_widget = new QStackedWidget();
|
||||
|
||||
if (app->config->display_driver == "vulkan")
|
||||
{
|
||||
canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this);
|
||||
QGuiApplication::processEvents();
|
||||
canvas->createContext();
|
||||
}
|
||||
else if (app->config->display_driver == "opengl")
|
||||
{
|
||||
canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this);
|
||||
QGuiApplication::processEvents();
|
||||
app->emu_thread->runOnThread([&] { canvas->createContext(); }, true);
|
||||
}
|
||||
|
||||
central_widget->addWidget(canvas);
|
||||
central_widget->setCurrentWidget(canvas);
|
||||
setCentralWidget(central_widget);
|
||||
using_stacked_widget = true;
|
||||
QGuiApplication::processEvents();
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (app->config->display_driver == "vulkan")
|
||||
{
|
||||
canvas = new EmuCanvasVulkan(app->config.get(), this, this);
|
||||
QGuiApplication::processEvents();
|
||||
canvas->createContext();
|
||||
}
|
||||
else if (app->config->display_driver == "opengl")
|
||||
{
|
||||
canvas = new EmuCanvasOpenGL(app->config.get(), this, this);
|
||||
QGuiApplication::processEvents();
|
||||
app->emu_thread->runOnThread([&] { canvas->createContext(); }, true);
|
||||
}
|
||||
else
|
||||
canvas = new EmuCanvasQt(app->config.get(), this, this);
|
||||
|
||||
|
@ -447,6 +465,7 @@ bool EmuMainWindow::event(QEvent *event)
|
|||
{
|
||||
toggleFullscreen();
|
||||
}
|
||||
app->stopThread();
|
||||
if (canvas)
|
||||
canvas->deinit();
|
||||
QGuiApplication::sync();
|
||||
|
@ -530,13 +549,24 @@ void EmuMainWindow::toggleFullscreen()
|
|||
|
||||
bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == canvas && event->type() == QEvent::Resize)
|
||||
if (watched == canvas)
|
||||
{
|
||||
app->suspendThread();
|
||||
canvas->resizeEvent((QResizeEvent *)event);
|
||||
event->accept();
|
||||
app->unsuspendThread();
|
||||
return true;
|
||||
if (event->type() == QEvent::Resize)
|
||||
{
|
||||
app->suspendThread();
|
||||
canvas->resizeEvent((QResizeEvent *)event);
|
||||
event->accept();
|
||||
app->unsuspendThread();
|
||||
return true;
|
||||
}
|
||||
else if (event->type() == QEvent::Paint)
|
||||
{
|
||||
app->emu_thread->runOnThread([&] {
|
||||
canvas->paintEvent((QPaintEvent *)event);
|
||||
}, true);
|
||||
event->accept();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease)
|
||||
|
|
|
@ -17,6 +17,8 @@ int main(int argc, char *argv[])
|
|||
signal(s, quit_handler);
|
||||
#endif
|
||||
|
||||
emu.startThread();
|
||||
|
||||
emu.config = std::make_unique<EmuConfig>();
|
||||
emu.config->setDefaults();
|
||||
emu.config->loadFile(EmuConfig::findConfigFile());
|
||||
|
@ -27,7 +29,6 @@ int main(int argc, char *argv[])
|
|||
|
||||
emu.updateBindings();
|
||||
emu.startInputTimer();
|
||||
emu.startThread();
|
||||
emu.qtapp->exec();
|
||||
|
||||
emu.stopThread();
|
||||
|
|
Loading…
Reference in New Issue