Qt: Rip out OpenGL proxy thread

This commit is contained in:
Vicki Pfau 2023-04-18 20:15:57 -07:00
parent 7337edb82a
commit 727ba5b2f2
2 changed files with 20 additions and 152 deletions

View File

@ -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) {
@ -365,7 +344,6 @@ void DisplayGL::stopDrawing() {
hide();
}
setUpdatesEnabled(true);
m_threadStartPending &= ~1;
}
m_context.reset();
}
@ -490,35 +468,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();
}
void DisplayGL::updateContentSize() {
QMetaObject::invokeMethod(m_painter.get(), "contentSize", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QSize, m_cachedContentSize));
}
@ -593,12 +547,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
@ -666,11 +614,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();
@ -821,7 +767,6 @@ void PainterGL::start() {
}
#endif
resizeContext();
m_context->addFrameAction(std::bind(&PainterGL::swapTex, this));
m_buffer = nullptr;
m_active = true;
@ -830,7 +775,7 @@ void PainterGL::start() {
}
void PainterGL::draw() {
if (!m_started || (m_queue.isEmpty() && m_queueTex.isEmpty())) {
if (!m_started || m_queue.isEmpty()) {
return;
}
@ -916,6 +861,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() {
@ -943,33 +893,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()) {
@ -979,19 +918,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[VIDEO_LAYER_IMAGE] = m_bridgeTexOut;
}
#endif
}
}
void PainterGL::dequeueAll(bool keep) {
@ -1012,19 +938,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) {
@ -1112,23 +1025,6 @@ 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::setBackgroundImage(const QImage& image) {
if (!m_started) {
makeCurrent();
@ -1150,14 +1046,4 @@ void PainterGL::setBackgroundImage(const QImage& image) {
}
}
void PainterGL::swapTex() {
if (!m_started) {
return;
}
CoreController::Interrupter interrupter(m_context);
emit texSwapped();
m_context->addFrameAction(std::bind(&PainterGL::swapTex, this));
}
#endif

View File

@ -122,8 +122,6 @@ protected:
virtual void resizeEvent(QResizeEvent*) override;
private slots:
void startThread(int);
void setupProxyThread();
void updateContentSize();
private:
@ -134,14 +132,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;
QSize m_cachedContentSize;
};
@ -156,7 +150,6 @@ public:
void setContext(std::shared_ptr<CoreController>);
void setMessagePainter(MessagePainter*);
void enqueue(const uint32_t* backing);
void enqueue(GLuint tex);
void stop();
@ -168,9 +161,6 @@ public:
void setVideoProxy(std::shared_ptr<VideoProxy>);
void interrupt();
// Run on main thread
void swapTex();
public slots:
void create();
void destroy();
@ -189,7 +179,6 @@ public slots:
void filter(bool filter);
void swapInterval(int interval);
void resizeContext();
void updateFramebufferHandle();
void setBackgroundImage(const QImage&);
void setShaders(struct VDir*);
@ -217,13 +206,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;