Threading fixes.

This commit is contained in:
BearOso 2023-07-14 16:17:35 -05:00
parent a438d3fa42
commit e42dd27cd1
10 changed files with 67 additions and 54 deletions

2
external/glslang vendored

@ -1 +1 @@
Subproject commit 9c7fd1a33e5cecbe465e1cd70170167d5e40d398 Subproject commit 3ebb72cc7429f0ab8218104dc3687c659c0f364d

View File

@ -2,6 +2,7 @@
#include "common/audio/s9x_sound_driver_sdl.hpp" #include "common/audio/s9x_sound_driver_sdl.hpp"
#include "common/audio/s9x_sound_driver_cubeb.hpp" #include "common/audio/s9x_sound_driver_cubeb.hpp"
#include <qlabel.h> #include <qlabel.h>
#include <qnamespace.h>
#ifdef USE_PULSEAUDIO #ifdef USE_PULSEAUDIO
#include "common/audio/s9x_sound_driver_pulse.hpp" #include "common/audio/s9x_sound_driver_pulse.hpp"
#endif #endif
@ -169,9 +170,7 @@ void EmuApplication::suspendThread()
if (suspend_count > 0) if (suspend_count > 0)
{ {
printf("Suspend %d\n", suspend_count); emu_thread->runOnThread([&] { emu_thread->setStatusBits(EmuThread::eSuspended); }, true);
emu_thread->runOnThread([&] { emu_thread->setStatusBits(EmuThread::eSuspended); });
emu_thread->waitForStatusBit(EmuThread::eSuspended);
} }
} }
@ -183,12 +182,9 @@ void EmuApplication::unsuspendThread()
if (!emu_thread) if (!emu_thread)
return; return;
printf("Un Suspend %d\n", suspend_count);
if (suspend_count == 0) if (suspend_count == 0)
{ {
emu_thread->runOnThread([&] { emu_thread->unsetStatusBits(EmuThread::eSuspended); }); emu_thread->runOnThread([&] { emu_thread->unsetStatusBits(EmuThread::eSuspended); }, true);
emu_thread->waitForStatusBitCleared(EmuThread::eSuspended);
} }
} }
@ -260,7 +256,6 @@ void EmuApplication::mainLoop()
return; return;
} }
printf("Here\n");
core->mainLoop(); core->mainLoop();
} }
@ -522,11 +517,15 @@ bool EmuApplication::isCoreActive()
return core->active; return core->active;
} }
void EmuThread::runOnThread(std::function<void()> func) void EmuThread::runOnThread(std::function<void()> func, bool blocking)
{ {
if (QThread::currentThread() != this) 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; return;
} }
@ -541,20 +540,12 @@ EmuThread::EmuThread(QThread *main_thread_)
void EmuThread::setStatusBits(int new_status) void EmuThread::setStatusBits(int new_status)
{ {
std::unique_lock lock(status_mutex);
status |= new_status; status |= new_status;
lock.unlock();
status_cond.notify_all();
} }
void EmuThread::unsetStatusBits(int new_status) void EmuThread::unsetStatusBits(int new_status)
{ {
printf("Old: %08x, new: %08x\n", status, new_status);
std::unique_lock lock(status_mutex);
status &= ~new_status; status &= ~new_status;
printf("Final: %08x\n", status);
lock.unlock();
status_cond.notify_all();
} }
void EmuThread::waitForStatusBit(int new_status) void EmuThread::waitForStatusBit(int new_status)
@ -564,8 +555,7 @@ void EmuThread::waitForStatusBit(int new_status)
while (1) while (1)
{ {
std::unique_lock lock(status_mutex); QThread::yieldCurrentThread();
status_cond.wait_for(lock, std::chrono::milliseconds(500));
if (status & new_status) if (status & new_status)
break; break;
} }
@ -578,8 +568,7 @@ void EmuThread::waitForStatusBitCleared(int new_status)
while (1) while (1)
{ {
std::unique_lock lock(status_mutex); QThread::yieldCurrentThread();
status_cond.wait_for(lock, std::chrono::milliseconds(500));
if (!(status & new_status)) if (!(status & new_status))
break; break;
} }
@ -587,14 +576,12 @@ void EmuThread::waitForStatusBitCleared(int new_status)
void EmuThread::pause() void EmuThread::pause()
{ {
runOnThread([&] { setStatusBits(ePaused); }); runOnThread([&] { setStatusBits(ePaused); }, true);
waitForStatusBit(ePaused);
} }
void EmuThread::unpause() void EmuThread::unpause()
{ {
runOnThread([&] { unsetStatusBits(ePaused); }); runOnThread([&] { unsetStatusBits(ePaused); }, true);
waitForStatusBitCleared(ePaused);
} }
void EmuThread::run() void EmuThread::run()
@ -612,12 +599,10 @@ void EmuThread::run()
if (status & (ePaused | eSuspended)) if (status & (ePaused | eSuspended))
{ {
std::this_thread::sleep_for(2ms); QThread::usleep(2000);
printf("Paused: %08x\n", status);
continue; continue;
} }
printf("Loop\n");
if (main_loop) if (main_loop)
main_loop(); main_loop();
} }

View File

@ -36,11 +36,9 @@ Q_OBJECT
}; };
int status = eDead; int status = eDead;
std::mutex status_mutex;
std::condition_variable status_cond;
public slots: public slots:
void runOnThread(std::function<void()> func); void runOnThread(std::function<void()> func, bool blocking = false);
}; };
struct EmuApplication struct EmuApplication

View File

@ -12,6 +12,8 @@ class EmuCanvas : public QWidget
virtual void deinit() = 0; virtual void deinit() = 0;
virtual void draw() = 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 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; void resizeEvent(QResizeEvent *event) override = 0;

View File

@ -57,11 +57,6 @@ EmuCanvasOpenGL::EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *ma
setAttribute(Qt::WA_OpaquePaintEvent); setAttribute(Qt::WA_OpaquePaintEvent);
createWinId(); createWinId();
auto timer = new QTimer(this);
timer->setSingleShot(true);
timer->callOnTimeout([&]{ createContext(); });
timer->start();
} }
EmuCanvasOpenGL::~EmuCanvasOpenGL() EmuCanvasOpenGL::~EmuCanvasOpenGL()
@ -251,6 +246,7 @@ void EmuCanvasOpenGL::draw()
return; return;
context->make_current(); context->make_current();
gladLoaderLoadGL();
uploadTexture(); uploadTexture();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@ -298,7 +294,8 @@ void EmuCanvasOpenGL::resizeEvent(QResizeEvent *event)
{ {
QWidget::resizeEvent(event); QWidget::resizeEvent(event);
if (!context) return; if (!context)
return;
auto g = parent->geometry(); auto g = parent->geometry();
int s = devicePixelRatio(); 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 }); ((WaylandEGLContext *)context.get())->resize({ g.x(), g.y(), g.width(), g.height(), s });
else if (platform == "xcb") else if (platform == "xcb")
((GTKGLXContext *)context.get())->resize(); ((GTKGLXContext *)context.get())->resize();
#else
((WGLContext *)context.get())->resize();
#endif #endif
} }
@ -324,6 +323,9 @@ void EmuCanvasOpenGL::paintEvent(QPaintEvent *event)
return; return;
} }
#ifdef _WIN32
((WGLContext *)context.get())->resize();
#endif
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
context->swap_buffers(); context->swap_buffers();

View File

@ -14,6 +14,7 @@ class EmuCanvasOpenGL : public EmuCanvas
EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window); EmuCanvasOpenGL(EmuConfig *config, QWidget *parent, QWidget *main_window);
~EmuCanvasOpenGL(); ~EmuCanvasOpenGL();
void createContext() override;
void deinit() override; void deinit() override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
@ -26,7 +27,6 @@ class EmuCanvasOpenGL : public EmuCanvas
private: private:
void resizeTexture(int width, int height); void resizeTexture(int width, int height);
void createContext();
void createStockShaders(); void createStockShaders();
void stockShaderDraw(); void stockShaderDraw();
void customShaderDraw(); void customShaderDraw();

View File

@ -25,11 +25,6 @@ EmuCanvasVulkan::EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *ma
createWinId(); createWinId();
window = windowHandle(); window = windowHandle();
auto timer = new QTimer(this);
timer->setSingleShot(true);
timer->callOnTimeout([&]{ createContext(); });
timer->start();
} }
EmuCanvasVulkan::~EmuCanvasVulkan() EmuCanvasVulkan::~EmuCanvasVulkan()

View File

@ -16,6 +16,7 @@ class EmuCanvasVulkan : public EmuCanvas
EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window); EmuCanvasVulkan(EmuConfig *config, QWidget *parent, QWidget *main_window);
~EmuCanvasVulkan(); ~EmuCanvasVulkan();
void createContext();
void deinit() override; void deinit() override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
@ -37,7 +38,6 @@ class EmuCanvasVulkan : public EmuCanvas
std::unique_ptr<Vulkan::ShaderChain> shader_chain; std::unique_ptr<Vulkan::ShaderChain> shader_chain;
private: private:
void createContext();
void tryLoadShader(); void tryLoadShader();
std::string current_shader; std::string current_shader;
QWindow *window = nullptr; QWindow *window = nullptr;

View File

@ -84,22 +84,40 @@ void EmuMainWindow::createCanvas()
auto central_widget = new QStackedWidget(); auto central_widget = new QStackedWidget();
if (app->config->display_driver == "vulkan") if (app->config->display_driver == "vulkan")
{
canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this); canvas = new EmuCanvasVulkan(app->config.get(), central_widget, this);
QGuiApplication::processEvents();
canvas->createContext();
}
else if (app->config->display_driver == "opengl") else if (app->config->display_driver == "opengl")
{
canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this); canvas = new EmuCanvasOpenGL(app->config.get(), central_widget, this);
QGuiApplication::processEvents();
app->emu_thread->runOnThread([&] { canvas->createContext(); }, true);
}
central_widget->addWidget(canvas); central_widget->addWidget(canvas);
central_widget->setCurrentWidget(canvas); central_widget->setCurrentWidget(canvas);
setCentralWidget(central_widget); setCentralWidget(central_widget);
using_stacked_widget = true; using_stacked_widget = true;
QGuiApplication::processEvents();
return; return;
} }
#endif #endif
if (app->config->display_driver == "vulkan") if (app->config->display_driver == "vulkan")
{
canvas = new EmuCanvasVulkan(app->config.get(), this, this); canvas = new EmuCanvasVulkan(app->config.get(), this, this);
QGuiApplication::processEvents();
canvas->createContext();
}
else if (app->config->display_driver == "opengl") else if (app->config->display_driver == "opengl")
{
canvas = new EmuCanvasOpenGL(app->config.get(), this, this); canvas = new EmuCanvasOpenGL(app->config.get(), this, this);
QGuiApplication::processEvents();
app->emu_thread->runOnThread([&] { canvas->createContext(); }, true);
}
else else
canvas = new EmuCanvasQt(app->config.get(), this, this); canvas = new EmuCanvasQt(app->config.get(), this, this);
@ -447,6 +465,7 @@ bool EmuMainWindow::event(QEvent *event)
{ {
toggleFullscreen(); toggleFullscreen();
} }
app->stopThread();
if (canvas) if (canvas)
canvas->deinit(); canvas->deinit();
QGuiApplication::sync(); QGuiApplication::sync();
@ -530,13 +549,24 @@ void EmuMainWindow::toggleFullscreen()
bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event) bool EmuMainWindow::eventFilter(QObject *watched, QEvent *event)
{ {
if (watched == canvas && event->type() == QEvent::Resize) if (watched == canvas)
{ {
app->suspendThread(); if (event->type() == QEvent::Resize)
canvas->resizeEvent((QResizeEvent *)event); {
event->accept(); app->suspendThread();
app->unsuspendThread(); canvas->resizeEvent((QResizeEvent *)event);
return true; 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) if (event->type() != QEvent::KeyPress && event->type() != QEvent::KeyRelease)

View File

@ -17,6 +17,8 @@ int main(int argc, char *argv[])
signal(s, quit_handler); signal(s, quit_handler);
#endif #endif
emu.startThread();
emu.config = std::make_unique<EmuConfig>(); emu.config = std::make_unique<EmuConfig>();
emu.config->setDefaults(); emu.config->setDefaults();
emu.config->loadFile(EmuConfig::findConfigFile()); emu.config->loadFile(EmuConfig::findConfigFile());
@ -27,7 +29,6 @@ int main(int argc, char *argv[])
emu.updateBindings(); emu.updateBindings();
emu.startInputTimer(); emu.startInputTimer();
emu.startThread();
emu.qtapp->exec(); emu.qtapp->exec();
emu.stopThread(); emu.stopThread();