Qt: Simplify Window drawing (fixes #2190)

This commit is contained in:
Vicki Pfau 2022-06-06 17:21:02 -07:00
parent 97cb18d3fd
commit ae0c5e91aa
7 changed files with 59 additions and 70 deletions

View File

@ -57,6 +57,7 @@ Other fixes:
- Qt: Fix some hangs when using the debugger console - Qt: Fix some hangs when using the debugger console
- Qt: Fix crash when clicking past last tile in viewer - Qt: Fix crash when clicking past last tile in viewer
- Qt: Fix preloading for ROM replacing - Qt: Fix preloading for ROM replacing
- Qt: Fix screen not displaying on Wayland (fixes mgba.io/i/2190)
- VFS: Failed file mapping should return NULL on POSIX - VFS: Failed file mapping should return NULL on POSIX
Misc: Misc:
- Core: Suspend runloop when a core crashes - Core: Suspend runloop when a core crashes

View File

@ -56,10 +56,13 @@ uint qHash(const QSurfaceFormat& format, uint seed) {
} }
void mGLWidget::initializeGL() { void mGLWidget::initializeGL() {
m_vao.create(); m_vao = std::make_unique<QOpenGLVertexArrayObject>();
m_program.create(); m_vao->create();
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, R"(#version 150 core m_program = std::make_unique<QOpenGLShaderProgram>();
m_program->create();
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, R"(#version 150 core
in vec4 position; in vec4 position;
out vec2 texCoord; out vec2 texCoord;
void main() { void main() {
@ -67,7 +70,7 @@ void mGLWidget::initializeGL() {
texCoord = (position.st + 1.0) * 0.5; texCoord = (position.st + 1.0) * 0.5;
})"); })");
m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, R"(#version 150 core m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, R"(#version 150 core
in vec2 texCoord; in vec2 texCoord;
out vec4 color; out vec4 color;
uniform sampler2D tex; uniform sampler2D tex;
@ -75,9 +78,9 @@ void mGLWidget::initializeGL() {
color = vec4(texture(tex, texCoord).rgb, 1.0); color = vec4(texture(tex, texCoord).rgb, 1.0);
})"); })");
m_program.link(); m_program->link();
m_program.setUniformValue("tex", 0); m_program->setUniformValue("tex", 0);
m_positionLocation = m_program.attributeLocation("position"); m_positionLocation = m_program->attributeLocation("position");
connect(&m_refresh, &QTimer::timeout, this, static_cast<void (QWidget::*)()>(&QWidget::update)); connect(&m_refresh, &QTimer::timeout, this, static_cast<void (QWidget::*)()>(&QWidget::update));
} }
@ -85,11 +88,11 @@ void mGLWidget::initializeGL() {
void mGLWidget::finalizeVAO() { void mGLWidget::finalizeVAO() {
QOpenGLFunctions_Baseline* fn = context()->versionFunctions<QOpenGLFunctions_Baseline>(); QOpenGLFunctions_Baseline* fn = context()->versionFunctions<QOpenGLFunctions_Baseline>();
fn->glGetError(); // Clear the error fn->glGetError(); // Clear the error
m_vao.bind(); m_vao->bind();
fn->glBindBuffer(GL_ARRAY_BUFFER, m_vbo); fn->glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
fn->glEnableVertexAttribArray(m_positionLocation); fn->glEnableVertexAttribArray(m_positionLocation);
fn->glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL); fn->glVertexAttribPointer(m_positionLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
m_vao.release(); m_vao->release();
if (fn->glGetError() == GL_NO_ERROR) { if (fn->glGetError() == GL_NO_ERROR) {
m_vaoDone = true; m_vaoDone = true;
} }
@ -100,13 +103,13 @@ void mGLWidget::paintGL() {
finalizeVAO(); finalizeVAO();
} }
QOpenGLFunctions_Baseline* fn = context()->versionFunctions<QOpenGLFunctions_Baseline>(); QOpenGLFunctions_Baseline* fn = context()->versionFunctions<QOpenGLFunctions_Baseline>();
m_program.bind(); m_program->bind();
m_vao.bind(); m_vao->bind();
fn->glBindTexture(GL_TEXTURE_2D, m_tex); fn->glBindTexture(GL_TEXTURE_2D, m_tex);
fn->glDrawArrays(GL_TRIANGLE_FAN, 0, 4); fn->glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
fn->glBindTexture(GL_TEXTURE_2D, 0); fn->glBindTexture(GL_TEXTURE_2D, 0);
m_vao.release(); m_vao->release();
m_program.release(); m_program->release();
// TODO: Better timing // TODO: Better timing
++m_refreshResidue; ++m_refreshResidue;

View File

@ -32,6 +32,7 @@
#include <QTimer> #include <QTimer>
#include <array> #include <array>
#include <memory>
#include "CoreController.h" #include "CoreController.h"
#include "VideoProxy.h" #include "VideoProxy.h"
@ -62,8 +63,8 @@ private:
GLuint m_vbo; GLuint m_vbo;
bool m_vaoDone = false; bool m_vaoDone = false;
QOpenGLVertexArrayObject m_vao; std::unique_ptr<QOpenGLVertexArrayObject> m_vao;
QOpenGLShaderProgram m_program; std::unique_ptr<QOpenGLShaderProgram> m_program;
GLuint m_positionLocation; GLuint m_positionLocation;
QTimer m_refresh; QTimer m_refresh;

View File

@ -9,6 +9,7 @@
#include "GamepadAxisEvent.h" #include "GamepadAxisEvent.h"
#include "GamepadButtonEvent.h" #include "GamepadButtonEvent.h"
#include "VFileDevice.h" #include "VFileDevice.h"
#include "utils.h"
#include <QAction> #include <QAction>
#include <QDateTime> #include <QDateTime>
@ -251,6 +252,10 @@ void LoadSaveState::focusInEvent(QFocusEvent*) {
void LoadSaveState::paintEvent(QPaintEvent*) { void LoadSaveState::paintEvent(QPaintEvent*) {
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
QRect full(QPoint(), size()); QRect full(QPoint(), size());
painter.fillRect(full, Qt::black);
painter.drawPixmap(clampSize(m_dims, size(), m_lockAspectRatio, m_lockIntegerScaling), m_background);
painter.fillRect(full, QColor(0, 0, 0, 128)); painter.fillRect(full, QColor(0, 0, 0, 128));
} }

View File

@ -32,6 +32,10 @@ public:
void setInputController(InputController* controller); void setInputController(InputController* controller);
void setMode(LoadSave mode); void setMode(LoadSave mode);
void setBackground(const QPixmap& pixmap) { m_background = pixmap; }
void setDimensions(const QSize& dims) { m_dims = dims; }
void setLockIntegerScaling(bool lockIntegerScaling) { m_lockIntegerScaling = lockIntegerScaling; }
void setLockAspectRatio(bool lockApsectRatio) { m_lockAspectRatio = lockApsectRatio; }
signals: signals:
void closed(); void closed();
@ -54,6 +58,11 @@ private:
int m_currentFocus; int m_currentFocus;
QPixmap m_currentImage; QPixmap m_currentImage;
QPixmap m_background;
QSize m_dims;
bool m_lockAspectRatio;
bool m_lockIntegerScaling;
}; };
} }

View File

@ -12,7 +12,6 @@
#include <QMimeData> #include <QMimeData>
#include <QPainter> #include <QPainter>
#include <QScreen> #include <QScreen>
#include <QStackedLayout>
#include <QWindow> #include <QWindow>
#ifdef USE_SQLITE3 #ifdef USE_SQLITE3
@ -58,7 +57,6 @@
#include "TileView.h" #include "TileView.h"
#include "VideoProxy.h" #include "VideoProxy.h"
#include "VideoView.h" #include "VideoView.h"
#include "utils.h"
#ifdef USE_DISCORD_RPC #ifdef USE_DISCORD_RPC
#include "DiscordCoordinator.h" #include "DiscordCoordinator.h"
@ -113,14 +111,12 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
m_libraryView = new LibraryController(nullptr, ConfigController::configDir() + "/library.sqlite3", m_config); m_libraryView = new LibraryController(nullptr, ConfigController::configDir() + "/library.sqlite3", m_config);
ConfigOption* showLibrary = m_config->addOption("showLibrary"); ConfigOption* showLibrary = m_config->addOption("showLibrary");
showLibrary->connect([this](const QVariant& value) { showLibrary->connect([this](const QVariant& value) {
if (value.toBool()) { if (!m_controller) {
if (m_controller) { if (value.toBool()) {
m_screenWidget->layout()->addWidget(m_libraryView);
} else {
attachWidget(m_libraryView); attachWidget(m_libraryView);
} else {
attachWidget(m_screenWidget);
} }
} else {
detachWidget(m_libraryView);
} }
}, this); }, this);
m_config->updateOption("showLibrary"); m_config->updateOption("showLibrary");
@ -150,7 +146,6 @@ Window::Window(CoreManager* manager, ConfigController* config, int playerId, QWi
resizeFrame(QSize(GB_VIDEO_HORIZONTAL_PIXELS * i, GB_VIDEO_VERTICAL_PIXELS * i)); resizeFrame(QSize(GB_VIDEO_HORIZONTAL_PIXELS * i, GB_VIDEO_VERTICAL_PIXELS * i));
#endif #endif
setLogo(); setLogo();
setCentralWidget(m_screenWidget);
connect(this, &Window::shutdown, m_logView, &QWidget::hide); connect(this, &Window::shutdown, m_logView, &QWidget::hide);
connect(&m_fpsTimer, &QTimer::timeout, this, &Window::showFPS); connect(&m_fpsTimer, &QTimer::timeout, this, &Window::showFPS);
@ -883,7 +878,6 @@ void Window::gameStarted() {
action.value()->setEnabled(m_controller->platform() == action.key()); action.value()->setEnabled(m_controller->platform() == action.key());
} }
QSize size = m_controller->screenDimensions(); QSize size = m_controller->screenDimensions();
m_screenWidget->setDimensions(size.width(), size.height());
m_config->updateOption("lockIntegerScaling"); m_config->updateOption("lockIntegerScaling");
m_config->updateOption("lockAspectRatio"); m_config->updateOption("lockAspectRatio");
m_config->updateOption("interframeBlending"); m_config->updateOption("interframeBlending");
@ -977,7 +971,6 @@ void Window::gameStopped() {
m_audioProcessor.reset(); m_audioProcessor.reset();
} }
m_display->stopDrawing(); m_display->stopDrawing();
detachWidget(m_display.get());
setLogo(); setLogo();
if (m_display) { if (m_display) {
#ifdef M_CORE_GB #ifdef M_CORE_GB
@ -988,6 +981,7 @@ void Window::gameStopped() {
} }
m_controller.reset(); m_controller.reset();
detachWidget();
updateTitle(); updateTitle();
if (m_pendingClose) { if (m_pendingClose) {
@ -1039,7 +1033,7 @@ void Window::unimplementedBiosCall(int) {
void Window::reloadDisplayDriver() { void Window::reloadDisplayDriver() {
if (m_controller) { if (m_controller) {
m_display->stopDrawing(); m_display->stopDrawing();
detachWidget(m_display.get()); detachWidget();
} }
m_display = std::unique_ptr<QGBA::Display>(Display::create(this)); m_display = std::unique_ptr<QGBA::Display>(Display::create(this));
if (!m_display) { if (!m_display) {
@ -1054,7 +1048,7 @@ void Window::reloadDisplayDriver() {
#endif #endif
connect(m_display.get(), &QGBA::Display::hideCursor, [this]() { connect(m_display.get(), &QGBA::Display::hideCursor, [this]() {
if (static_cast<QStackedLayout*>(m_screenWidget->layout())->currentWidget() == m_display.get()) { if (centralWidget() == m_display.get()) {
m_screenWidget->setCursor(Qt::BlankCursor); m_screenWidget->setCursor(Qt::BlankCursor);
} }
}); });
@ -1215,15 +1209,13 @@ void Window::openStateWindow(LoadSave ls) {
m_stateWindow = new LoadSaveState(m_controller); m_stateWindow = new LoadSaveState(m_controller);
connect(this, &Window::shutdown, m_stateWindow, &QWidget::close); connect(this, &Window::shutdown, m_stateWindow, &QWidget::close);
connect(m_stateWindow, &LoadSaveState::closed, [this]() { connect(m_stateWindow, &LoadSaveState::closed, [this]() {
detachWidget(m_stateWindow); attachWidget(m_display.get());
static_cast<QStackedLayout*>(m_screenWidget->layout())->setCurrentWidget(m_display.get());
m_stateWindow = nullptr; m_stateWindow = nullptr;
QMetaObject::invokeMethod(this, "setFocus", Qt::QueuedConnection); QMetaObject::invokeMethod(this, "setFocus", Qt::QueuedConnection);
}); });
if (!wasPaused) { if (!wasPaused) {
m_controller->setPaused(true); m_controller->setPaused(true);
connect(m_stateWindow, &LoadSaveState::closed, [this]() { connect(m_stateWindow, &LoadSaveState::closed, [this]() {
m_screenWidget->filter(m_config->getOption("resampleVideo").toInt());
if (m_controller) { if (m_controller) {
m_controller->setPaused(false); m_controller->setPaused(false);
} }
@ -1232,6 +1224,10 @@ void Window::openStateWindow(LoadSave ls) {
m_stateWindow->setAttribute(Qt::WA_DeleteOnClose); m_stateWindow->setAttribute(Qt::WA_DeleteOnClose);
m_stateWindow->setMode(ls); m_stateWindow->setMode(ls);
m_stateWindow->setDimensions(m_controller->screenDimensions());
m_config->updateOption("lockAspectRatio");
m_config->updateOption("lockIntegerScaling");
QImage still(m_controller->getPixels()); QImage still(m_controller->getPixels());
if (still.format() != QImage::Format_RGB888) { if (still.format() != QImage::Format_RGB888) {
still = still.convertToFormat(QImage::Format_RGB888); still = still.convertToFormat(QImage::Format_RGB888);
@ -1249,8 +1245,7 @@ void Window::openStateWindow(LoadSave ls) {
QPixmap pixmap; QPixmap pixmap;
pixmap.convertFromImage(output); pixmap.convertFromImage(output);
m_screenWidget->setPixmap(pixmap); m_stateWindow->setBackground(pixmap);
m_screenWidget->filter(true);
#ifndef Q_OS_MAC #ifndef Q_OS_MAC
menuBar()->show(); menuBar()->show();
@ -1536,8 +1531,8 @@ void Window::setupMenu(QMenuBar* menubar) {
if (m_display) { if (m_display) {
m_display->lockAspectRatio(value.toBool()); m_display->lockAspectRatio(value.toBool());
} }
if (m_controller) { if (m_stateWindow) {
m_screenWidget->setLockAspectRatio(value.toBool()); m_stateWindow->setLockAspectRatio(value.toBool());
} }
}, this); }, this);
m_config->updateOption("lockAspectRatio"); m_config->updateOption("lockAspectRatio");
@ -1548,8 +1543,8 @@ void Window::setupMenu(QMenuBar* menubar) {
if (m_display) { if (m_display) {
m_display->lockIntegerScaling(value.toBool()); m_display->lockIntegerScaling(value.toBool());
} }
if (m_controller) { if (m_stateWindow) {
m_screenWidget->setLockIntegerScaling(value.toBool()); m_stateWindow->setLockIntegerScaling(value.toBool());
} }
}, this); }, this);
m_config->updateOption("lockIntegerScaling"); m_config->updateOption("lockIntegerScaling");
@ -1569,9 +1564,6 @@ void Window::setupMenu(QMenuBar* menubar) {
if (m_display) { if (m_display) {
m_display->filter(value.toBool()); m_display->filter(value.toBool());
} }
if (m_controller) {
m_screenWidget->filter(value.toBool());
}
}, this); }, this);
m_config->updateOption("resampleVideo"); m_config->updateOption("resampleVideo");
@ -1894,13 +1886,12 @@ void Window::setupOptions() {
} }
void Window::attachWidget(QWidget* widget) { void Window::attachWidget(QWidget* widget) {
m_screenWidget->layout()->addWidget(widget); takeCentralWidget();
m_screenWidget->unsetCursor(); setCentralWidget(widget);
static_cast<QStackedLayout*>(m_screenWidget->layout())->setCurrentWidget(widget);
} }
void Window::detachWidget(QWidget* widget) { void Window::detachWidget() {
m_screenWidget->layout()->removeWidget(widget); m_config->updateOption("showLibrary");
} }
void Window::appendMRU(const QString& fname) { void Window::appendMRU(const QString& fname) {
@ -1996,7 +1987,7 @@ void Window::focusCheck() {
} }
void Window::updateFrame() { void Window::updateFrame() {
if (static_cast<QStackedLayout*>(m_screenWidget->layout())->currentWidget() != m_display.get()) { if (!m_controller) {
return; return;
} }
QPixmap pixmap; QPixmap pixmap;
@ -2171,17 +2162,12 @@ void Window::updateMute() {
void Window::setLogo() { void Window::setLogo() {
m_screenWidget->setPixmap(m_logo); m_screenWidget->setPixmap(m_logo);
m_screenWidget->setDimensions(m_logo.width(), m_logo.height()); m_screenWidget->setDimensions(m_logo.width(), m_logo.height());
m_screenWidget->setLockIntegerScaling(false);
m_screenWidget->setLockAspectRatio(true);
m_screenWidget->filter(true);
m_screenWidget->unsetCursor(); m_screenWidget->unsetCursor();
} }
WindowBackground::WindowBackground(QWidget* parent) WindowBackground::WindowBackground(QWidget* parent)
: QWidget(parent) : QWidget(parent)
{ {
setLayout(new QStackedLayout());
layout()->setContentsMargins(0, 0, 0, 0);
} }
void WindowBackground::setPixmap(const QPixmap& pmap) { void WindowBackground::setPixmap(const QPixmap& pmap) {
@ -2202,24 +2188,12 @@ void WindowBackground::setDimensions(int width, int height) {
m_aspectHeight = height; m_aspectHeight = height;
} }
void WindowBackground::setLockIntegerScaling(bool lock) {
m_lockIntegerScaling = lock;
}
void WindowBackground::setLockAspectRatio(bool lock) {
m_lockAspectRatio = lock;
}
void WindowBackground::filter(bool filter) {
m_filter = filter;
}
void WindowBackground::paintEvent(QPaintEvent* event) { void WindowBackground::paintEvent(QPaintEvent* event) {
QWidget::paintEvent(event); QWidget::paintEvent(event);
const QPixmap& logo = pixmap(); const QPixmap& logo = pixmap();
QPainter painter(this); QPainter painter(this);
painter.setRenderHint(QPainter::SmoothPixmapTransform, m_filter); painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
painter.fillRect(QRect(QPoint(), size()), Qt::black); painter.fillRect(QRect(QPoint(), size()), Qt::black);
QRect full(clampSize(QSize(m_aspectWidth, m_aspectHeight), size(), m_lockAspectRatio, m_lockIntegerScaling)); QRect full(clampSize(QSize(m_aspectWidth, m_aspectHeight), size(), true, false));
painter.drawPixmap(full, logo); painter.drawPixmap(full, logo);
} }

View File

@ -167,7 +167,7 @@ private:
void openStateWindow(LoadSave); void openStateWindow(LoadSave);
void attachWidget(QWidget* widget); void attachWidget(QWidget* widget);
void detachWidget(QWidget* widget); void detachWidget();
void appendMRU(const QString& fname); void appendMRU(const QString& fname);
void clearMRU(); void clearMRU();
@ -277,7 +277,6 @@ public:
void setDimensions(int width, int height); void setDimensions(int width, int height);
void setLockIntegerScaling(bool lock); void setLockIntegerScaling(bool lock);
void setLockAspectRatio(bool lock); void setLockAspectRatio(bool lock);
void filter(bool filter);
const QPixmap& pixmap() const { return m_pixmap; } const QPixmap& pixmap() const { return m_pixmap; }
@ -289,9 +288,6 @@ private:
QSize m_sizeHint; QSize m_sizeHint;
int m_aspectWidth; int m_aspectWidth;
int m_aspectHeight; int m_aspectHeight;
bool m_lockAspectRatio;
bool m_lockIntegerScaling;
bool m_filter;
}; };
} }