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_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();
}

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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()

View File

@ -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;

View File

@ -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)

View File

@ -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();