mirror of https://github.com/mgba-emu/mgba.git
Qt: Rip out OpenGL proxy thread
This commit is contained in:
parent
70bbe06bfb
commit
2f2287683a
|
@ -63,11 +63,6 @@ typedef struct _XDisplay Display;
|
|||
|
||||
using namespace QGBA;
|
||||
|
||||
enum ThreadStartFrom {
|
||||
START = 1,
|
||||
PROXY = 2,
|
||||
};
|
||||
|
||||
QHash<QSurfaceFormat, bool> DisplayGL::s_supports;
|
||||
|
||||
uint qHash(const QSurfaceFormat& format, uint seed) {
|
||||
|
@ -221,11 +216,6 @@ DisplayGL::DisplayGL(const QSurfaceFormat& format, QWidget* parent)
|
|||
m_drawThread.setObjectName("Painter Thread");
|
||||
m_painter->setThread(&m_drawThread);
|
||||
|
||||
m_proxyThread.setObjectName("OpenGL Proxy Thread");
|
||||
m_proxyContext = std::make_unique<QOpenGLContext>();
|
||||
m_proxyContext->setFormat(format);
|
||||
connect(m_painter.get(), &PainterGL::created, this, &DisplayGL::setupProxyThread);
|
||||
|
||||
connect(&m_drawThread, &QThread::started, m_painter.get(), &PainterGL::create);
|
||||
connect(m_painter.get(), &PainterGL::started, this, [this] {
|
||||
m_hasStarted = true;
|
||||
|
@ -240,11 +230,6 @@ DisplayGL::~DisplayGL() {
|
|||
QMetaObject::invokeMethod(m_painter.get(), "destroy", Qt::BlockingQueuedConnection);
|
||||
m_drawThread.exit();
|
||||
m_drawThread.wait();
|
||||
|
||||
if (m_proxyThread.isRunning()) {
|
||||
m_proxyThread.exit();
|
||||
m_proxyThread.wait();
|
||||
}
|
||||
}
|
||||
|
||||
bool DisplayGL::supportsShaders() const {
|
||||
|
@ -265,6 +250,9 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
|
|||
m_painter->setContext(controller);
|
||||
m_painter->setMessagePainter(messagePainter());
|
||||
m_context = controller;
|
||||
if (videoProxy()) {
|
||||
videoProxy()->moveToThread(&m_drawThread);
|
||||
}
|
||||
|
||||
lockAspectRatio(isAspectRatioLocked());
|
||||
lockIntegerScaling(isIntegerScalingLocked());
|
||||
|
@ -279,15 +267,6 @@ void DisplayGL::startDrawing(std::shared_ptr<CoreController> controller) {
|
|||
messagePainter()->resize(size(), devicePixelRatio());
|
||||
#endif
|
||||
|
||||
startThread(ThreadStartFrom::START);
|
||||
}
|
||||
|
||||
void DisplayGL::startThread(int from) {
|
||||
m_threadStartPending |= from;
|
||||
if (m_threadStartPending < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
CoreController::Interrupter interrupter(m_context);
|
||||
QMetaObject::invokeMethod(m_painter.get(), "start");
|
||||
if (!m_gl) {
|
||||
|
@ -363,7 +342,6 @@ void DisplayGL::stopDrawing() {
|
|||
hide();
|
||||
}
|
||||
setUpdatesEnabled(true);
|
||||
m_threadStartPending &= ~1;
|
||||
}
|
||||
m_context.reset();
|
||||
}
|
||||
|
@ -481,35 +459,11 @@ bool DisplayGL::shouldDisableUpdates() {
|
|||
void DisplayGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) {
|
||||
Display::setVideoProxy(proxy);
|
||||
if (proxy) {
|
||||
proxy->moveToThread(&m_proxyThread);
|
||||
proxy->moveToThread(&m_drawThread);
|
||||
}
|
||||
m_painter->setVideoProxy(proxy);
|
||||
}
|
||||
|
||||
void DisplayGL::setupProxyThread() {
|
||||
m_proxyContext->moveToThread(&m_proxyThread);
|
||||
m_proxySurface.create();
|
||||
connect(&m_proxyThread, &QThread::started, m_proxyContext.get(), [this]() {
|
||||
m_proxyContext->setShareContext(m_painter->shareContext());
|
||||
m_proxyContext->create();
|
||||
m_proxyContext->makeCurrent(&m_proxySurface);
|
||||
#if defined(_WIN32) && defined(USE_EPOXY)
|
||||
epoxy_handle_external_wglMakeCurrent();
|
||||
#endif
|
||||
QMetaObject::invokeMethod(this, "startThread", Q_ARG(int, ThreadStartFrom::PROXY));
|
||||
});
|
||||
connect(m_painter.get(), &PainterGL::texSwapped, m_proxyContext.get(), [this]() {
|
||||
if (!m_context->hardwareAccelerated()) {
|
||||
return;
|
||||
}
|
||||
if (videoProxy()) {
|
||||
videoProxy()->processData();
|
||||
}
|
||||
m_painter->updateFramebufferHandle();
|
||||
}, Qt::BlockingQueuedConnection);
|
||||
m_proxyThread.start();
|
||||
}
|
||||
|
||||
int DisplayGL::framebufferHandle() {
|
||||
return m_painter->glTex();
|
||||
}
|
||||
|
@ -580,12 +534,6 @@ void PainterGL::create() {
|
|||
gl2Backend = static_cast<mGLES2Context*>(malloc(sizeof(mGLES2Context)));
|
||||
mGLES2ContextCreate(gl2Backend);
|
||||
m_backend = &gl2Backend->d;
|
||||
QOpenGLFunctions* fn = m_gl->functions();
|
||||
fn->glGenTextures(m_bridgeTexes.size(), m_bridgeTexes.data());
|
||||
for (auto tex : m_bridgeTexes) {
|
||||
m_freeTex.enqueue(tex);
|
||||
}
|
||||
m_bridgeTexIn = m_freeTex.dequeue();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -653,11 +601,9 @@ void PainterGL::destroy() {
|
|||
}
|
||||
makeCurrent();
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
QOpenGLFunctions* fn = m_gl->functions();
|
||||
if (m_shader.passes) {
|
||||
mGLES2ShaderFree(&m_shader);
|
||||
}
|
||||
fn->glDeleteTextures(m_bridgeTexes.size(), m_bridgeTexes.data());
|
||||
#endif
|
||||
m_backend->deinit(m_backend);
|
||||
m_gl->doneCurrent();
|
||||
|
@ -783,7 +729,6 @@ void PainterGL::start() {
|
|||
}
|
||||
#endif
|
||||
resizeContext();
|
||||
m_context->addFrameAction(std::bind(&PainterGL::swapTex, this));
|
||||
|
||||
m_buffer = nullptr;
|
||||
m_active = true;
|
||||
|
@ -792,7 +737,7 @@ void PainterGL::start() {
|
|||
}
|
||||
|
||||
void PainterGL::draw() {
|
||||
if (!m_started || (m_queue.isEmpty() && m_queueTex.isEmpty())) {
|
||||
if (!m_started || m_queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -878,6 +823,11 @@ void PainterGL::doStop() {
|
|||
}
|
||||
m_backend->clear(m_backend);
|
||||
m_backend->swap(m_backend);
|
||||
if (m_videoProxy) {
|
||||
m_videoProxy->reset();
|
||||
m_videoProxy->moveToThread(m_window->thread());
|
||||
m_videoProxy.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::pause() {
|
||||
|
@ -905,33 +855,22 @@ void PainterGL::performDraw() {
|
|||
}
|
||||
|
||||
void PainterGL::enqueue(const uint32_t* backing) {
|
||||
if (!backing) {
|
||||
return;
|
||||
}
|
||||
QMutexLocker locker(&m_mutex);
|
||||
uint32_t* buffer = nullptr;
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
}
|
||||
if (buffer) {
|
||||
QSize size = m_context->screenDimensions();
|
||||
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
|
||||
if (backing) {
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
}
|
||||
if (buffer) {
|
||||
QSize size = m_context->screenDimensions();
|
||||
memcpy(buffer, backing, size.width() * size.height() * BYTES_PER_PIXEL);
|
||||
}
|
||||
}
|
||||
m_queue.enqueue(buffer);
|
||||
}
|
||||
|
||||
void PainterGL::enqueue(GLuint tex) {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (m_freeTex.isEmpty()) {
|
||||
m_bridgeTexIn = m_queueTex.dequeue();
|
||||
} else {
|
||||
m_bridgeTexIn = m_freeTex.takeLast();
|
||||
}
|
||||
m_queueTex.enqueue(tex);
|
||||
}
|
||||
|
||||
void PainterGL::dequeue() {
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (!m_queue.isEmpty()) {
|
||||
|
@ -941,19 +880,6 @@ void PainterGL::dequeue() {
|
|||
}
|
||||
m_buffer = buffer;
|
||||
}
|
||||
|
||||
if (!m_queueTex.isEmpty()) {
|
||||
if (m_bridgeTexOut != std::numeric_limits<GLuint>::max()) {
|
||||
m_freeTex.enqueue(m_bridgeTexOut);
|
||||
}
|
||||
m_bridgeTexOut = m_queueTex.dequeue();
|
||||
#if defined(BUILD_GLES2) || defined(BUILD_GLES3)
|
||||
if (supportsShaders()) {
|
||||
mGLES2Context* gl2Backend = reinterpret_cast<mGLES2Context*>(m_backend);
|
||||
gl2Backend->tex = m_bridgeTexOut;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::dequeueAll(bool keep) {
|
||||
|
@ -974,19 +900,6 @@ void PainterGL::dequeueAll(bool keep) {
|
|||
m_free.append(m_buffer);
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
|
||||
m_queueTex.clear();
|
||||
m_freeTex.clear();
|
||||
for (auto tex : m_bridgeTexes) {
|
||||
if (keep && tex == m_bridgeTexIn) {
|
||||
continue;
|
||||
}
|
||||
m_freeTex.enqueue(tex);
|
||||
}
|
||||
if (!keep) {
|
||||
m_bridgeTexIn = m_freeTex.dequeue();
|
||||
m_bridgeTexOut = std::numeric_limits<GLuint>::max();
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::setVideoProxy(std::shared_ptr<VideoProxy> proxy) {
|
||||
|
@ -1067,31 +980,4 @@ QOpenGLContext* PainterGL::shareContext() {
|
|||
}
|
||||
}
|
||||
|
||||
void PainterGL::updateFramebufferHandle() {
|
||||
QOpenGLFunctions* fn = m_gl->functions();
|
||||
// TODO: Figure out why glFlush doesn't work here on Intel/Windows
|
||||
if (glContextHasBug(OpenGLBug::CROSS_THREAD_FLUSH)) {
|
||||
fn->glFinish();
|
||||
} else {
|
||||
fn->glFlush();
|
||||
}
|
||||
|
||||
CoreController::Interrupter interrupter(m_context);
|
||||
if (!m_context->hardwareAccelerated()) {
|
||||
return;
|
||||
}
|
||||
enqueue(m_bridgeTexIn);
|
||||
m_context->setFramebufferHandle(m_bridgeTexIn);
|
||||
}
|
||||
|
||||
void PainterGL::swapTex() {
|
||||
if (!m_started) {
|
||||
return;
|
||||
}
|
||||
|
||||
CoreController::Interrupter interrupter(m_context);
|
||||
emit texSwapped();
|
||||
m_context->addFrameAction(std::bind(&PainterGL::swapTex, this));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -119,10 +119,6 @@ protected:
|
|||
virtual void paintEvent(QPaintEvent*) override { forceDraw(); }
|
||||
virtual void resizeEvent(QResizeEvent*) override;
|
||||
|
||||
private slots:
|
||||
void startThread(int);
|
||||
void setupProxyThread();
|
||||
|
||||
private:
|
||||
void resizePainter();
|
||||
bool shouldDisableUpdates();
|
||||
|
@ -131,14 +127,10 @@ private:
|
|||
|
||||
bool m_isDrawing = false;
|
||||
bool m_hasStarted = false;
|
||||
int m_threadStartPending = 0;
|
||||
std::unique_ptr<PainterGL> m_painter;
|
||||
QThread m_drawThread;
|
||||
QThread m_proxyThread;
|
||||
std::shared_ptr<CoreController> m_context;
|
||||
mGLWidget* m_gl;
|
||||
QOffscreenSurface m_proxySurface;
|
||||
std::unique_ptr<QOpenGLContext> m_proxyContext;
|
||||
};
|
||||
|
||||
class PainterGL : public QObject {
|
||||
|
@ -152,7 +144,6 @@ public:
|
|||
void setContext(std::shared_ptr<CoreController>);
|
||||
void setMessagePainter(MessagePainter*);
|
||||
void enqueue(const uint32_t* backing);
|
||||
void enqueue(GLuint tex);
|
||||
|
||||
void stop();
|
||||
|
||||
|
@ -164,9 +155,6 @@ public:
|
|||
void setVideoProxy(std::shared_ptr<VideoProxy>);
|
||||
void interrupt();
|
||||
|
||||
// Run on main thread
|
||||
void swapTex();
|
||||
|
||||
public slots:
|
||||
void create();
|
||||
void destroy();
|
||||
|
@ -185,7 +173,6 @@ public slots:
|
|||
void filter(bool filter);
|
||||
void swapInterval(int interval);
|
||||
void resizeContext();
|
||||
void updateFramebufferHandle();
|
||||
|
||||
void setShaders(struct VDir*);
|
||||
void clearShaders();
|
||||
|
@ -210,13 +197,6 @@ private:
|
|||
QQueue<uint32_t*> m_queue;
|
||||
uint32_t* m_buffer = nullptr;
|
||||
|
||||
std::array<GLuint, 3> m_bridgeTexes;
|
||||
QQueue<GLuint> m_freeTex;
|
||||
QQueue<GLuint> m_queueTex;
|
||||
|
||||
GLuint m_bridgeTexIn = std::numeric_limits<GLuint>::max();
|
||||
GLuint m_bridgeTexOut = std::numeric_limits<GLuint>::max();
|
||||
|
||||
QPainter m_painter;
|
||||
QMutex m_mutex;
|
||||
QWindow* m_window;
|
||||
|
|
Loading…
Reference in New Issue