mirror of https://github.com/mgba-emu/mgba.git
Qt: Add checking and downgrading OpenGL support outside of the painter
This commit is contained in:
parent
e31de6b470
commit
a8a7372083
1
CHANGES
1
CHANGES
|
@ -78,6 +78,7 @@ Other fixes:
|
||||||
- Qt: Fix gamepad event dispatching (fixes mgba.io/i/1922)
|
- Qt: Fix gamepad event dispatching (fixes mgba.io/i/1922)
|
||||||
- Qt: Pre-attach GDB stub when launching with -g (fixes mgba.io/i/1950)
|
- Qt: Pre-attach GDB stub when launching with -g (fixes mgba.io/i/1950)
|
||||||
- Qt: Fix crash when editing shortcuts with none selected (fixes mgba.io/i/1964)
|
- Qt: Fix crash when editing shortcuts with none selected (fixes mgba.io/i/1964)
|
||||||
|
- Qt: Fix crashing when no OpenGL context can be obtained
|
||||||
- SM83: Simplify register pair access on big endian
|
- SM83: Simplify register pair access on big endian
|
||||||
- SM83: Disassemble STOP as one byte
|
- SM83: Disassemble STOP as one byte
|
||||||
- Wii: Fix crash on unloading irregularly sized GBA ROMs
|
- Wii: Fix crash on unloading irregularly sized GBA ROMs
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "DisplayGL.h"
|
#include "DisplayGL.h"
|
||||||
#include "DisplayQt.h"
|
#include "DisplayQt.h"
|
||||||
|
#include "LogController.h"
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
@ -27,16 +28,31 @@ Display* Display::create(QWidget* parent) {
|
||||||
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
#if defined(BUILD_GL) || defined(BUILD_GLES2) || defined(USE_EPOXY)
|
||||||
case Driver::OPENGL:
|
case Driver::OPENGL:
|
||||||
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
|
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
|
||||||
format.setVersion(3, 0);
|
format.setVersion(2, 0);
|
||||||
} else {
|
} else {
|
||||||
format.setVersion(3, 2);
|
format.setVersion(3, 2);
|
||||||
}
|
}
|
||||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||||
|
if (!DisplayGL::supportsFormat(format)) {
|
||||||
|
#ifdef BUILD_GL
|
||||||
|
LOG(QT, WARN) << ("Failed to create an OpenGL Core context, trying old-style...");
|
||||||
|
format.setVersion(1, 4);
|
||||||
|
format.setOption(QSurfaceFormat::DeprecatedFunctions);
|
||||||
|
if (!DisplayGL::supportsFormat(format)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
return new DisplayGL(format, parent);
|
return new DisplayGL(format, parent);
|
||||||
#endif
|
#endif
|
||||||
#ifdef BUILD_GL
|
#ifdef BUILD_GL
|
||||||
case Driver::OPENGL1:
|
case Driver::OPENGL1:
|
||||||
format.setVersion(1, 4);
|
format.setVersion(1, 4);
|
||||||
|
if (!DisplayGL::supportsFormat(format)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
return new DisplayGL(format, parent);
|
return new DisplayGL(format, parent);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,10 @@
|
||||||
#include "CoreController.h"
|
#include "CoreController.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QOffscreenSurface>
|
||||||
#include <QOpenGLContext>
|
#include <QOpenGLContext>
|
||||||
#include <QOpenGLPaintDevice>
|
#include <QOpenGLPaintDevice>
|
||||||
#include <QMutexLocker>
|
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
@ -34,6 +35,15 @@
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
|
QHash<QSurfaceFormat, bool> DisplayGL::s_supports;
|
||||||
|
|
||||||
|
uint qHash(const QSurfaceFormat& format, uint seed) {
|
||||||
|
QByteArray representation;
|
||||||
|
QDataStream stream(&representation, QIODevice::WriteOnly);
|
||||||
|
stream << format.version() << format.renderableType() << format.profile();
|
||||||
|
return qHash(representation, seed);
|
||||||
|
}
|
||||||
|
|
||||||
DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent)
|
DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent)
|
||||||
: Display(parent)
|
: Display(parent)
|
||||||
{
|
{
|
||||||
|
@ -98,6 +108,44 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
|
||||||
setUpdatesEnabled(false);
|
setUpdatesEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DisplayGL::supportsFormat(const QSurfaceFormat& format) {
|
||||||
|
if (!s_supports.contains(format)) {
|
||||||
|
QOpenGLContext context;
|
||||||
|
context.setFormat(format);
|
||||||
|
if (!context.create()) {
|
||||||
|
s_supports[format] = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto foundVersion = context.format().version();
|
||||||
|
if (foundVersion == format.version()) {
|
||||||
|
// Match!
|
||||||
|
s_supports[format] = true;
|
||||||
|
} else if (format.version() >= qMakePair(3, 2) && foundVersion > format.version()) {
|
||||||
|
// At least as good
|
||||||
|
s_supports[format] = true;
|
||||||
|
} else if (format.majorVersion() == 1 && (foundVersion < qMakePair(3, 0) ||
|
||||||
|
context.format().profile() == QSurfaceFormat::CompatibilityProfile ||
|
||||||
|
context.format().testOption(QSurfaceFormat::DeprecatedFunctions))) {
|
||||||
|
// Supports the old stuff
|
||||||
|
s_supports[format] = true;
|
||||||
|
} else if (!context.isOpenGLES() && format.version() >= qMakePair(2, 1) && foundVersion < qMakePair(3, 0) && foundVersion >= qMakePair(2, 1)) {
|
||||||
|
// Weird edge case we support if ARB_framebuffer_object is present
|
||||||
|
QOffscreenSurface surface;
|
||||||
|
surface.create();
|
||||||
|
if (!context.makeCurrent(&surface)) {
|
||||||
|
s_supports[format] = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
s_supports[format] = context.hasExtension("GL_ARB_framebuffer_object");
|
||||||
|
context.doneCurrent();
|
||||||
|
} else {
|
||||||
|
// No match
|
||||||
|
s_supports[format] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s_supports[format];
|
||||||
|
}
|
||||||
|
|
||||||
void DisplayGL::stopDrawing() {
|
void DisplayGL::stopDrawing() {
|
||||||
if (m_drawThread) {
|
if (m_drawThread) {
|
||||||
m_isDrawing = false;
|
m_isDrawing = false;
|
||||||
|
@ -236,6 +284,7 @@ PainterGL::PainterGL(QWindow* surface, const QSurfaceFormat& format)
|
||||||
: m_surface(surface)
|
: m_surface(surface)
|
||||||
, m_format(format)
|
, m_format(format)
|
||||||
{
|
{
|
||||||
|
m_supportsShaders = m_format.version() >= qMakePair(2, 0);
|
||||||
for (auto& buf : m_buffers) {
|
for (auto& buf : m_buffers) {
|
||||||
m_free.append(&buf.front());
|
m_free.append(&buf.front());
|
||||||
}
|
}
|
||||||
|
@ -260,24 +309,6 @@ void PainterGL::create() {
|
||||||
m_gl->create();
|
m_gl->create();
|
||||||
makeCurrent();
|
makeCurrent();
|
||||||
|
|
||||||
auto version = m_gl->format().version();
|
|
||||||
QStringList extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' ');
|
|
||||||
|
|
||||||
int forceVersion = 0;
|
|
||||||
if (m_format.majorVersion() < 2) {
|
|
||||||
forceVersion = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((version == qMakePair(2, 1) && !extensions.contains("GL_ARB_framebuffer_object")) || version == qMakePair(2, 0)) {
|
|
||||||
QSurfaceFormat newFormat(m_format);
|
|
||||||
newFormat.setVersion(1, 4);
|
|
||||||
forceVersion = 1;
|
|
||||||
m_gl->doneCurrent();
|
|
||||||
m_gl->setFormat(newFormat);
|
|
||||||
m_gl->create();
|
|
||||||
makeCurrent();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef BUILD_GL
|
#ifdef BUILD_GL
|
||||||
mGLContext* glBackend;
|
mGLContext* glBackend;
|
||||||
#endif
|
#endif
|
||||||
|
@ -288,13 +319,11 @@ void PainterGL::create() {
|
||||||
m_window = std::make_unique<QOpenGLPaintDevice>();
|
m_window = std::make_unique<QOpenGLPaintDevice>();
|
||||||
|
|
||||||
#ifdef BUILD_GLES2
|
#ifdef BUILD_GLES2
|
||||||
version = m_gl->format().version();
|
auto version = m_format.version();
|
||||||
extensions = QString(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))).split(' ');
|
if (version >= qMakePair(2, 0)) {
|
||||||
if (forceVersion != 1 && ((version == qMakePair(2, 1) && extensions.contains("GL_ARB_framebuffer_object")) || version.first > 2)) {
|
|
||||||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||||
mGLES2ContextCreate(gl2Backend);
|
mGLES2ContextCreate(gl2Backend);
|
||||||
m_backend = &gl2Backend->d;
|
m_backend = &gl2Backend->d;
|
||||||
m_supportsShaders = true;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -303,7 +332,6 @@ void PainterGL::create() {
|
||||||
glBackend = static_cast<mGLContext*>(malloc(sizeof(mGLContext)));
|
glBackend = static_cast<mGLContext*>(malloc(sizeof(mGLContext)));
|
||||||
mGLContextCreate(glBackend);
|
mGLContextCreate(glBackend);
|
||||||
m_backend = &glBackend->d;
|
m_backend = &glBackend->d;
|
||||||
m_supportsShaders = false;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
m_backend->swap = [](VideoBackend* v) {
|
m_backend->swap = [](VideoBackend* v) {
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
|
|
||||||
#include <QAtomicInt>
|
#include <QAtomicInt>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QOpenGLContext>
|
#include <QHash>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
|
#include <QOpenGLContext>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
@ -34,6 +35,8 @@
|
||||||
|
|
||||||
class QOpenGLPaintDevice;
|
class QOpenGLPaintDevice;
|
||||||
|
|
||||||
|
uint qHash(const QSurfaceFormat&, uint seed = 0);
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
class PainterGL;
|
class PainterGL;
|
||||||
|
@ -51,6 +54,8 @@ public:
|
||||||
void setVideoProxy(std::shared_ptr<VideoProxy>) override;
|
void setVideoProxy(std::shared_ptr<VideoProxy>) override;
|
||||||
int framebufferHandle() override;
|
int framebufferHandle() override;
|
||||||
|
|
||||||
|
static bool supportsFormat(const QSurfaceFormat&);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void stopDrawing() override;
|
void stopDrawing() override;
|
||||||
void pauseDrawing() override;
|
void pauseDrawing() override;
|
||||||
|
@ -74,6 +79,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
void resizePainter();
|
void resizePainter();
|
||||||
|
|
||||||
|
static QHash<QSurfaceFormat, bool> s_supports;
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -884,6 +884,12 @@ void Window::reloadDisplayDriver() {
|
||||||
detachWidget(m_display.get());
|
detachWidget(m_display.get());
|
||||||
}
|
}
|
||||||
m_display = std::unique_ptr<Display>(Display::create(this));
|
m_display = std::unique_ptr<Display>(Display::create(this));
|
||||||
|
if (!m_display) {
|
||||||
|
LOG(QT, ERROR) << tr("Failed to create an appropriate display device, falling back to software display. "
|
||||||
|
"Games may run slowly, especially with larger windows.");
|
||||||
|
Display::setDriver(Display::Driver::QT);
|
||||||
|
m_display = std::unique_ptr<Display>(Display::create(this));
|
||||||
|
}
|
||||||
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
#if defined(BUILD_GL) || defined(BUILD_GLES2)
|
||||||
m_shaderView.reset();
|
m_shaderView.reset();
|
||||||
m_shaderView = std::make_unique<ShaderSelector>(m_display.get(), m_config);
|
m_shaderView = std::make_unique<ShaderSelector>(m_display.get(), m_config);
|
||||||
|
|
Loading…
Reference in New Issue