Qt: Always start painter thread even if not in use

This commit is contained in:
Vicki Pfau 2020-12-03 23:57:05 -08:00
parent d44a26d962
commit 2f7232292c
2 changed files with 54 additions and 86 deletions

View File

@ -51,10 +51,23 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent)
windowHandle()->create(); windowHandle()->create();
m_painter = std::make_unique<PainterGL>(windowHandle(), format); m_painter = std::make_unique<PainterGL>(windowHandle(), format);
m_drawThread.setObjectName("Painter Thread");
m_painter->moveToThread(&m_drawThread);
connect(&m_drawThread, &QThread::started, m_painter.get(), &PainterGL::create);
connect(m_painter.get(), &PainterGL::started, this, [this] {
m_hasStarted = true;
resizePainter();
emit drawingStarted();
});
m_drawThread.start();
} }
DisplayGL::~DisplayGL() { DisplayGL::~DisplayGL() {
stopDrawing(); stopDrawing();
QMetaObject::invokeMethod(m_painter.get(), "destroy", Qt::BlockingQueuedConnection);
m_drawThread.exit();
m_drawThread.wait();
} }
bool DisplayGL::supportsShaders() const { bool DisplayGL::supportsShaders() const {
@ -63,34 +76,21 @@ bool DisplayGL::supportsShaders() const {
VideoShader* DisplayGL::shaders() { VideoShader* DisplayGL::shaders() {
VideoShader* shaders = nullptr; VideoShader* shaders = nullptr;
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "shaders", Qt::BlockingQueuedConnection, Q_RETURN_ARG(VideoShader*, shaders)); QMetaObject::invokeMethod(m_painter.get(), "shaders", Qt::BlockingQueuedConnection, Q_RETURN_ARG(VideoShader*, shaders));
} else {
shaders = m_painter->shaders();
}
return shaders; return shaders;
} }
void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) { void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
if (m_drawThread) { if (m_isDrawing) {
return; return;
} }
m_isDrawing = true; m_isDrawing = true;
m_painter->setContext(controller); m_painter->setContext(controller);
m_painter->setMessagePainter(messagePainter()); m_painter->setMessagePainter(messagePainter());
m_context = controller; m_context = controller;
m_drawThread = new QThread(this);
m_drawThread->setObjectName("Painter Thread");
m_painter->moveToThread(m_drawThread);
if (videoProxy()) { if (videoProxy()) {
videoProxy()->moveToThread(m_drawThread); videoProxy()->moveToThread(&m_drawThread);
} }
connect(m_drawThread, &QThread::started, m_painter.get(), &PainterGL::start);
connect(m_painter.get(), &PainterGL::started, this, [this] {
m_hasStarted = true;
resizePainter();
emit drawingStarted();
});
lockAspectRatio(isAspectRatioLocked()); lockAspectRatio(isAspectRatioLocked());
lockIntegerScaling(isIntegerScalingLocked()); lockIntegerScaling(isIntegerScalingLocked());
@ -98,13 +98,12 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
showOSDMessages(isShowOSD()); showOSDMessages(isShowOSD());
filter(isFiltered()); filter(isFiltered());
m_drawThread->start();
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
messagePainter()->resize(size(), isAspectRatioLocked(), devicePixelRatioF()); messagePainter()->resize(size(), isAspectRatioLocked(), devicePixelRatioF());
#else #else
messagePainter()->resize(size(), isAspectRatioLocked(), devicePixelRatio()); messagePainter()->resize(size(), isAspectRatioLocked(), devicePixelRatio());
#endif #endif
QMetaObject::invokeMethod(m_painter.get(), "start");
setUpdatesEnabled(false); setUpdatesEnabled(false);
} }
@ -147,21 +146,18 @@ bool DisplayGL::supportsFormat(const QSurfaceFormat& format) {
} }
void DisplayGL::stopDrawing() { void DisplayGL::stopDrawing() {
if (m_drawThread) { if (m_hasStarted || m_isDrawing) {
m_isDrawing = false; m_isDrawing = false;
m_hasStarted = false; m_hasStarted = false;
CoreController::Interrupter interrupter(m_context); CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "stop", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter.get(), "stop", Qt::BlockingQueuedConnection);
m_drawThread->exit();
m_drawThread->wait();
m_drawThread = nullptr;
setUpdatesEnabled(true); setUpdatesEnabled(true);
} }
m_context.reset(); m_context.reset();
} }
void DisplayGL::pauseDrawing() { void DisplayGL::pauseDrawing() {
if (m_drawThread) { if (m_hasStarted) {
m_isDrawing = false; m_isDrawing = false;
CoreController::Interrupter interrupter(m_context); CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "pause", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter.get(), "pause", Qt::BlockingQueuedConnection);
@ -172,7 +168,7 @@ void DisplayGL::pauseDrawing() {
} }
void DisplayGL::unpauseDrawing() { void DisplayGL::unpauseDrawing() {
if (m_drawThread) { if (m_hasStarted) {
m_isDrawing = true; m_isDrawing = true;
CoreController::Interrupter interrupter(m_context); CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "unpause", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter.get(), "unpause", Qt::BlockingQueuedConnection);
@ -183,78 +179,59 @@ void DisplayGL::unpauseDrawing() {
} }
void DisplayGL::forceDraw() { void DisplayGL::forceDraw() {
if (m_drawThread) { if (m_hasStarted) {
QMetaObject::invokeMethod(m_painter.get(), "forceDraw"); QMetaObject::invokeMethod(m_painter.get(), "forceDraw");
} }
} }
void DisplayGL::lockAspectRatio(bool lock) { void DisplayGL::lockAspectRatio(bool lock) {
Display::lockAspectRatio(lock); Display::lockAspectRatio(lock);
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "lockAspectRatio", Q_ARG(bool, lock)); QMetaObject::invokeMethod(m_painter.get(), "lockAspectRatio", Q_ARG(bool, lock));
} }
}
void DisplayGL::lockIntegerScaling(bool lock) { void DisplayGL::lockIntegerScaling(bool lock) {
Display::lockIntegerScaling(lock); Display::lockIntegerScaling(lock);
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "lockIntegerScaling", Q_ARG(bool, lock)); QMetaObject::invokeMethod(m_painter.get(), "lockIntegerScaling", Q_ARG(bool, lock));
} }
}
void DisplayGL::interframeBlending(bool enable) { void DisplayGL::interframeBlending(bool enable) {
Display::interframeBlending(enable); Display::interframeBlending(enable);
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "interframeBlending", Q_ARG(bool, enable)); QMetaObject::invokeMethod(m_painter.get(), "interframeBlending", Q_ARG(bool, enable));
} }
}
void DisplayGL::showOSDMessages(bool enable) { void DisplayGL::showOSDMessages(bool enable) {
Display::showOSDMessages(enable); Display::showOSDMessages(enable);
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "showOSD", Q_ARG(bool, enable)); QMetaObject::invokeMethod(m_painter.get(), "showOSD", Q_ARG(bool, enable));
} }
}
void DisplayGL::filter(bool filter) { void DisplayGL::filter(bool filter) {
Display::filter(filter); Display::filter(filter);
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "filter", Q_ARG(bool, filter)); QMetaObject::invokeMethod(m_painter.get(), "filter", Q_ARG(bool, filter));
} }
}
void DisplayGL::framePosted() { void DisplayGL::framePosted() {
if (m_drawThread) {
m_painter->enqueue(m_context->drawContext()); m_painter->enqueue(m_context->drawContext());
QMetaObject::invokeMethod(m_painter.get(), "draw"); QMetaObject::invokeMethod(m_painter.get(), "draw");
} }
}
void DisplayGL::setShaders(struct VDir* shaders) { void DisplayGL::setShaders(struct VDir* shaders) {
if (m_drawThread) {
QMetaObject::invokeMethod(m_painter.get(), "setShaders", Qt::BlockingQueuedConnection, Q_ARG(struct VDir*, shaders)); QMetaObject::invokeMethod(m_painter.get(), "setShaders", Qt::BlockingQueuedConnection, Q_ARG(struct VDir*, shaders));
} else {
m_painter->setShaders(shaders);
}
} }
void DisplayGL::clearShaders() { void DisplayGL::clearShaders() {
QMetaObject::invokeMethod(m_painter.get(), "clearShaders"); QMetaObject::invokeMethod(m_painter.get(), "clearShaders", Qt::BlockingQueuedConnection);
} }
void DisplayGL::resizeContext() { void DisplayGL::resizeContext() {
if (m_drawThread) {
CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "resizeContext"); QMetaObject::invokeMethod(m_painter.get(), "resizeContext");
} }
}
void DisplayGL::setVideoScale(int scale) { void DisplayGL::setVideoScale(int scale) {
if (m_drawThread) { if (m_context) {
CoreController::Interrupter interrupter(m_context); CoreController::Interrupter interrupter(m_context);
mCoreConfigSetIntValue(&m_context->thread()->core->config, "videoScale", scale); mCoreConfigSetIntValue(&m_context->thread()->core->config, "videoScale", scale);
QMetaObject::invokeMethod(m_painter.get(), "resizeContext");
} }
QMetaObject::invokeMethod(m_painter.get(), "resizeContext");
} }
void DisplayGL::resizeEvent(QResizeEvent* event) { void DisplayGL::resizeEvent(QResizeEvent* event) {
@ -263,15 +240,15 @@ void DisplayGL::resizeEvent(QResizeEvent* event) {
} }
void DisplayGL::resizePainter() { void DisplayGL::resizePainter() {
if (m_drawThread && m_hasStarted) { if (m_hasStarted) {
QMetaObject::invokeMethod(m_painter.get(), "resize", Qt::BlockingQueuedConnection, Q_ARG(QSize, size())); QMetaObject::invokeMethod(m_painter.get(), "resize", Qt::BlockingQueuedConnection, Q_ARG(QSize, size()));
} }
} }
void DisplayGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) { void DisplayGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) {
Display::setVideoProxy(proxy); Display::setVideoProxy(proxy);
if (m_drawThread && proxy) { if (proxy) {
proxy->moveToThread(m_drawThread); proxy->moveToThread(&m_drawThread);
} }
m_painter->setVideoProxy(proxy); m_painter->setVideoProxy(proxy);
} }
@ -361,15 +338,6 @@ void PainterGL::destroy() {
return; return;
} }
makeCurrent(); makeCurrent();
if (m_context) {
if (m_videoProxy) {
m_videoProxy->detach(m_context.get());
}
m_context->setFramebufferHandle(-1);
if (m_videoProxy) {
m_videoProxy->processData();
}
}
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (m_shader.passes) { if (m_shader.passes) {
mGLES2ShaderFree(&m_shader); mGLES2ShaderFree(&m_shader);
@ -394,6 +362,7 @@ void PainterGL::resizeContext() {
} }
if (m_started) { if (m_started) {
CoreController::Interrupter interrupter(m_context);
mCore* core = m_context->thread()->core; mCore* core = m_context->thread()->core;
core->reloadConfigOption(core, "videoScale", NULL); core->reloadConfigOption(core, "videoScale", NULL);
} }
@ -440,9 +409,6 @@ void PainterGL::filter(bool filter) {
} }
void PainterGL::start() { void PainterGL::start() {
if (!m_gl) {
create();
}
makeCurrent(); makeCurrent();
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
@ -510,16 +476,23 @@ void PainterGL::stop() {
m_active = false; m_active = false;
m_started = false; m_started = false;
dequeueAll(); dequeueAll();
m_backend->clear(m_backend); if (m_context) {
m_backend->swap(m_backend); if (m_videoProxy) {
m_videoProxy->detach(m_context.get());
}
m_context->setFramebufferHandle(-1);
m_context.reset();
if (m_videoProxy) {
m_videoProxy->processData();
}
}
if (m_videoProxy) { if (m_videoProxy) {
m_videoProxy->reset(); m_videoProxy->reset();
}
destroy();
moveToThread(m_surface->thread());
if (m_videoProxy) {
m_videoProxy->moveToThread(m_surface->thread()); m_videoProxy->moveToThread(m_surface->thread());
m_videoProxy.reset();
} }
m_backend->clear(m_backend);
m_backend->swap(m_backend);
} }
void PainterGL::pause() { void PainterGL::pause() {
@ -606,9 +579,6 @@ void PainterGL::setShaders(struct VDir* dir) {
return; return;
} }
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (!m_started) {
return; // TODO
}
if (m_shader.passes) { if (m_shader.passes) {
mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend)); mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend));
mGLES2ShaderFree(&m_shader); mGLES2ShaderFree(&m_shader);
@ -623,9 +593,6 @@ void PainterGL::clearShaders() {
return; return;
} }
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (!m_started) {
return; // TODO
}
if (m_shader.passes) { if (m_shader.passes) {
mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend)); mGLES2ShaderDetach(reinterpret_cast<mGLES2Context*>(m_backend));
mGLES2ShaderFree(&m_shader); mGLES2ShaderFree(&m_shader);

View File

@ -84,7 +84,7 @@ private:
bool m_isDrawing = false; bool m_isDrawing = false;
bool m_hasStarted = false; bool m_hasStarted = false;
std::unique_ptr<PainterGL> m_painter; std::unique_ptr<PainterGL> m_painter;
QThread* m_drawThread = nullptr; QThread m_drawThread;
std::shared_ptr<CoreController> m_context; std::shared_ptr<CoreController> m_context;
}; };
@ -104,6 +104,9 @@ public:
void setVideoProxy(std::shared_ptr<VideoProxy>); void setVideoProxy(std::shared_ptr<VideoProxy>);
public slots: public slots:
void create();
void destroy();
void forceDraw(); void forceDraw();
void draw(); void draw();
void start(); void start();
@ -132,8 +135,6 @@ private:
void performDraw(); void performDraw();
void dequeue(); void dequeue();
void dequeueAll(); void dequeueAll();
void create();
void destroy();
std::array<std::array<uint32_t, 0x100000>, 3> m_buffers; std::array<std::array<uint32_t, 0x100000>, 3> m_buffers;
QList<uint32_t*> m_free; QList<uint32_t*> m_free;