Qt: Asynchronous drawing startup

This commit is contained in:
Vicki Pfau 2020-11-11 01:15:29 -08:00
parent 74edd964da
commit cb7f150cc2
6 changed files with 42 additions and 52 deletions

View File

@ -57,6 +57,7 @@ public:
std::shared_ptr<VideoProxy> videoProxy() { return m_videoProxy; } std::shared_ptr<VideoProxy> videoProxy() { return m_videoProxy; }
signals: signals:
void drawingStarted();
void showCursor(); void showCursor();
void hideCursor(); void hideCursor();

View File

@ -74,25 +74,32 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
videoProxy()->moveToThread(m_drawThread); videoProxy()->moveToThread(m_drawThread);
} }
connect(m_drawThread, &QThread::started, m_painter.get(), &PainterGL::start); connect(m_drawThread, &QThread::started, m_painter.get(), &PainterGL::start);
m_drawThread->start(); connect(m_painter.get(), &PainterGL::started, this, [this] {
m_hasStarted = true;
resizePainter();
emit drawingStarted();
});
lockAspectRatio(isAspectRatioLocked()); lockAspectRatio(isAspectRatioLocked());
lockIntegerScaling(isIntegerScalingLocked()); lockIntegerScaling(isIntegerScalingLocked());
interframeBlending(hasInterframeBlending()); interframeBlending(hasInterframeBlending());
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
resizePainter();
setUpdatesEnabled(false); setUpdatesEnabled(false);
} }
void DisplayGL::stopDrawing() { void DisplayGL::stopDrawing() {
if (m_drawThread) { if (m_drawThread) {
m_isDrawing = false; m_isDrawing = 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->exit();
@ -187,18 +194,16 @@ void DisplayGL::clearShaders() {
void DisplayGL::resizeContext() { void DisplayGL::resizeContext() {
if (m_drawThread) { if (m_drawThread) {
m_isDrawing = false;
CoreController::Interrupter interrupter(m_context); CoreController::Interrupter interrupter(m_context);
QMetaObject::invokeMethod(m_painter.get(), "resizeContext", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter.get(), "resizeContext");
} }
} }
void DisplayGL::setVideoScale(int scale) { void DisplayGL::setVideoScale(int scale) {
if (m_drawThread) { if (m_drawThread) {
m_isDrawing = false;
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", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(m_painter.get(), "resizeContext");
} }
} }
@ -208,7 +213,7 @@ void DisplayGL::resizeEvent(QResizeEvent* event) {
} }
void DisplayGL::resizePainter() { void DisplayGL::resizePainter() {
if (m_drawThread) { if (m_drawThread && 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()));
} }
} }
@ -240,15 +245,19 @@ PainterGL::~PainterGL() {
} }
} }
void PainterGL::create() { void PainterGL::makeCurrent() {
m_gl = std::make_unique<QOpenGLContext>();
m_gl->setFormat(m_format);
m_gl->create();
m_gl->makeCurrent(m_surface); m_gl->makeCurrent(m_surface);
#if defined(_WIN32) && defined(USE_EPOXY) #if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent(); epoxy_handle_external_wglMakeCurrent();
#endif #endif
}
void PainterGL::create() {
m_gl = std::make_unique<QOpenGLContext>();
m_gl->setFormat(m_format);
m_gl->create();
makeCurrent();
auto version = m_gl->format().version(); auto version = m_gl->format().version();
QStringList extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' '); QStringList extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' ');
@ -261,10 +270,11 @@ void PainterGL::create() {
QSurfaceFormat newFormat(m_format); QSurfaceFormat newFormat(m_format);
newFormat.setVersion(1, 4); newFormat.setVersion(1, 4);
forceVersion = 1; forceVersion = 1;
m_gl->doneCurrent();
m_gl->setFormat(newFormat); m_gl->setFormat(newFormat);
m_gl->create(); m_gl->create();
makeCurrent();
} }
m_gl->makeCurrent(m_surface);
#ifdef BUILD_GL #ifdef BUILD_GL
mGLContext* glBackend; mGLContext* glBackend;
@ -274,9 +284,6 @@ void PainterGL::create() {
#endif #endif
m_window = std::make_unique<QOpenGLPaintDevice>(); m_window = std::make_unique<QOpenGLPaintDevice>();
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
version = m_gl->format().version(); version = m_gl->format().version();
@ -303,10 +310,7 @@ void PainterGL::create() {
return; return;
} }
painter->m_gl->swapBuffers(painter->m_surface); painter->m_gl->swapBuffers(painter->m_surface);
painter->m_gl->makeCurrent(painter->m_surface); painter->makeCurrent();
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
}; };
m_backend->init(m_backend, 0); m_backend->init(m_backend, 0);
@ -326,10 +330,7 @@ void PainterGL::destroy() {
if (!m_gl) { if (!m_gl) {
return; return;
} }
m_gl->makeCurrent(m_surface); makeCurrent();
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
if (m_context) { if (m_context) {
if (m_videoProxy) { if (m_videoProxy) {
m_videoProxy->detach(m_context.get()); m_videoProxy->detach(m_context.get());
@ -412,10 +413,7 @@ void PainterGL::start() {
if (!m_gl) { if (!m_gl) {
create(); create();
} }
m_gl->makeCurrent(m_surface); makeCurrent();
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (m_supportsShaders && m_shader.passes) { if (m_supportsShaders && m_shader.passes) {
@ -427,6 +425,7 @@ void PainterGL::start() {
m_buffer = nullptr; m_buffer = nullptr;
m_active = true; m_active = true;
m_started = true; m_started = true;
emit started();
} }
void PainterGL::draw() { void PainterGL::draw() {
@ -559,21 +558,14 @@ void PainterGL::setShaders(struct VDir* dir) {
} }
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (!m_started) { if (!m_started) {
m_gl->makeCurrent(m_surface); return; // TODO
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
} }
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);
} }
mGLES2ShaderLoad(&m_shader, dir); mGLES2ShaderLoad(&m_shader, dir);
if (m_started) { mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses);
mGLES2ShaderAttach(reinterpret_cast<mGLES2Context*>(m_backend), static_cast<mGLES2Shader*>(m_shader.passes), m_shader.nPasses);
} else {
m_gl->doneCurrent();
}
#endif #endif
} }
@ -583,18 +575,12 @@ void PainterGL::clearShaders() {
} }
#ifdef BUILD_GLES2 #ifdef BUILD_GLES2
if (!m_started) { if (!m_started) {
m_gl->makeCurrent(m_surface); return; // TODO
#if defined(_WIN32) && defined(USE_EPOXY)
epoxy_handle_external_wglMakeCurrent();
#endif
} }
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);
} }
if (!m_started) {
m_gl->doneCurrent();
}
#endif #endif
} }

View File

@ -74,6 +74,7 @@ private:
void resizePainter(); void resizePainter();
bool m_isDrawing = false; bool m_isDrawing = false;
bool m_hasStarted = false;
std::unique_ptr<PainterGL> m_painter; std::unique_ptr<PainterGL> m_painter;
QThread* m_drawThread = nullptr; QThread* m_drawThread = nullptr;
std::shared_ptr<CoreController> m_context; std::shared_ptr<CoreController> m_context;
@ -115,7 +116,11 @@ public slots:
int glTex(); int glTex();
signals:
void started();
private: private:
void makeCurrent();
void performDraw(); void performDraw();
void dequeue(); void dequeue();
void dequeueAll(); void dequeueAll();

View File

@ -28,6 +28,7 @@ void DisplayQt::startDrawing(std::shared_ptr<CoreController> controller) {
m_oldBacking = std::move(QImage()); m_oldBacking = std::move(QImage());
m_isDrawing = true; m_isDrawing = true;
m_context = controller; m_context = controller;
emit drawingStarted();
} }
void DisplayQt::stopDrawing() { void DisplayQt::stopDrawing() {

View File

@ -831,7 +831,6 @@ void Window::gameStopped() {
m_controller.reset(); m_controller.reset();
updateTitle(); updateTitle();
m_display->setVideoProxy({});
if (m_pendingClose) { if (m_pendingClose) {
m_display.reset(); m_display.reset();
close(); close();
@ -919,7 +918,6 @@ void Window::reloadDisplayDriver() {
attachDisplay(); attachDisplay();
attachWidget(m_display.get()); attachWidget(m_display.get());
m_display->startDrawing(m_controller);
} }
#ifdef M_CORE_GB #ifdef M_CORE_GB
m_display->setMinimumSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS); m_display->setMinimumSize(GB_VIDEO_HORIZONTAL_PIXELS, GB_VIDEO_VERTICAL_PIXELS);
@ -964,6 +962,7 @@ void Window::changeRenderer() {
int fb = m_display->framebufferHandle(); int fb = m_display->framebufferHandle();
if (fb >= 0) { if (fb >= 0) {
m_controller->setFramebufferHandle(fb); m_controller->setFramebufferHandle(fb);
m_config->updateOption("videoScale");
} }
} else { } else {
m_controller->setFramebufferHandle(-1); m_controller->setFramebufferHandle(-1);
@ -1828,7 +1827,6 @@ void Window::setController(CoreController* controller, const QString& fname) {
m_inputController.recalibrateAxes(); m_inputController.recalibrateAxes();
m_controller->setInputController(&m_inputController); m_controller->setInputController(&m_inputController);
m_controller->setLogger(&m_log); m_controller->setLogger(&m_log);
m_display->startDrawing(m_controller);
connect(this, &Window::shutdown, [this]() { connect(this, &Window::shutdown, [this]() {
if (!m_controller) { if (!m_controller) {
@ -1862,9 +1860,6 @@ void Window::setController(CoreController* controller, const QString& fname) {
connect(m_controller.get(), &CoreController::unpaused, [this]() { connect(m_controller.get(), &CoreController::unpaused, [this]() {
emit paused(false); emit paused(false);
}); });
attachDisplay();
connect(m_controller.get(), &CoreController::unpaused, &m_inputController, &InputController::suspendScreensaver); connect(m_controller.get(), &CoreController::unpaused, &m_inputController, &InputController::suspendScreensaver);
connect(m_controller.get(), &CoreController::frameAvailable, this, &Window::recordFrame); connect(m_controller.get(), &CoreController::frameAvailable, this, &Window::recordFrame);
connect(m_controller.get(), &CoreController::crashed, this, &Window::gameCrashed); connect(m_controller.get(), &CoreController::crashed, this, &Window::gameCrashed);
@ -1906,6 +1901,7 @@ void Window::setController(CoreController* controller, const QString& fname) {
m_pendingPatch = QString(); m_pendingPatch = QString();
} }
attachDisplay();
m_controller->loadConfig(m_config); m_controller->loadConfig(m_config);
m_controller->start(); m_controller->start();
@ -1929,7 +1925,8 @@ void Window::attachDisplay() {
connect(m_controller.get(), &CoreController::frameAvailable, m_display.get(), &Display::framePosted); connect(m_controller.get(), &CoreController::frameAvailable, m_display.get(), &Display::framePosted);
connect(m_controller.get(), &CoreController::statusPosted, m_display.get(), &Display::showMessage); connect(m_controller.get(), &CoreController::statusPosted, m_display.get(), &Display::showMessage);
connect(m_controller.get(), &CoreController::didReset, m_display.get(), &Display::resizeContext); connect(m_controller.get(), &CoreController::didReset, m_display.get(), &Display::resizeContext);
changeRenderer(); connect(m_display.get(), &Display::drawingStarted, this, &Window::changeRenderer);
m_display->startDrawing(m_controller);
} }
void Window::setLogo() { void Window::setLogo() {

View File

@ -131,6 +131,7 @@ private slots:
void reloadAudioDriver(); void reloadAudioDriver();
void reloadDisplayDriver(); void reloadDisplayDriver();
void attachDisplay();
void changeRenderer(); void changeRenderer();
void tryMakePortable(); void tryMakePortable();
@ -159,7 +160,6 @@ private:
void updateMRU(); void updateMRU();
void openView(QWidget* widget); void openView(QWidget* widget);
void attachDisplay();
template <typename T, typename... A> std::function<void()> openTView(A... arg); template <typename T, typename... A> std::function<void()> openTView(A... arg);
template <typename T, typename... A> std::function<void()> openControllerTView(A... arg); template <typename T, typename... A> std::function<void()> openControllerTView(A... arg);