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; }
signals:
void drawingStarted();
void showCursor();
void hideCursor();

View File

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

View File

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

View File

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

View File

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

View File

@ -131,6 +131,7 @@ private slots:
void reloadAudioDriver();
void reloadDisplayDriver();
void attachDisplay();
void changeRenderer();
void tryMakePortable();
@ -159,7 +160,6 @@ private:
void updateMRU();
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()> openControllerTView(A... arg);