mirror of https://github.com/mgba-emu/mgba.git
Qt: Fix sync, hopefully
This commit is contained in:
parent
581d5fab3b
commit
870c8ebb8c
1
CHANGES
1
CHANGES
|
@ -30,6 +30,7 @@ Features:
|
|||
- Libretro now supports BIOS, rumble and solar sensor
|
||||
- Implement BIOS call Stop, for sleep mode
|
||||
- Automatically load patches, if found
|
||||
- Improved video synchronization
|
||||
Bugfixes:
|
||||
- ARM7: Fix SWI and IRQ timings
|
||||
- GBA Audio: Force audio FIFOs to 32-bit
|
||||
|
|
|
@ -118,7 +118,8 @@ void DisplayGL::filter(bool filter) {
|
|||
|
||||
void DisplayGL::framePosted(const uint32_t* buffer) {
|
||||
if (m_drawThread && buffer) {
|
||||
QMetaObject::invokeMethod(m_painter, "setBacking", Q_ARG(const uint32_t*, buffer));
|
||||
m_painter->enqueue(buffer);
|
||||
QMetaObject::invokeMethod(m_painter, "draw");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -152,6 +153,19 @@ PainterGL::PainterGL(QGLWidget* parent)
|
|||
m_backend.d.user = this;
|
||||
m_backend.d.filter = false;
|
||||
m_backend.d.lockAspectRatio = false;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
m_free.append(new uint32_t[256 * 256]);
|
||||
}
|
||||
}
|
||||
|
||||
PainterGL::~PainterGL() {
|
||||
while (!m_queue.isEmpty()) {
|
||||
delete[] m_queue.dequeue();
|
||||
}
|
||||
for (auto item : m_free) {
|
||||
delete[] item;
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::setContext(GBAThread* context) {
|
||||
|
@ -162,15 +176,6 @@ void PainterGL::setMessagePainter(MessagePainter* messagePainter) {
|
|||
m_messagePainter = messagePainter;
|
||||
}
|
||||
|
||||
void PainterGL::setBacking(const uint32_t* backing) {
|
||||
m_gl->makeCurrent();
|
||||
m_backend.d.postFrame(&m_backend.d, backing);
|
||||
if (m_active) {
|
||||
draw();
|
||||
}
|
||||
m_gl->doneCurrent();
|
||||
}
|
||||
|
||||
void PainterGL::resize(const QSize& size) {
|
||||
m_size = size;
|
||||
if (m_active) {
|
||||
|
@ -200,7 +205,11 @@ void PainterGL::start() {
|
|||
}
|
||||
|
||||
void PainterGL::draw() {
|
||||
if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip)) {
|
||||
if (m_queue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (GBASyncWaitFrameStart(&m_context->sync, m_context->frameskip) || !m_queue.isEmpty()) {
|
||||
dequeue();
|
||||
m_painter.begin(m_gl->context()->device());
|
||||
performDraw();
|
||||
m_painter.end();
|
||||
|
@ -209,6 +218,9 @@ void PainterGL::draw() {
|
|||
} else {
|
||||
GBASyncWaitFrameEnd(&m_context->sync);
|
||||
}
|
||||
if (!m_queue.isEmpty()) {
|
||||
QMetaObject::invokeMethod(this, "draw", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::forceDraw() {
|
||||
|
@ -221,6 +233,7 @@ void PainterGL::forceDraw() {
|
|||
void PainterGL::stop() {
|
||||
m_active = false;
|
||||
m_gl->makeCurrent();
|
||||
dequeueAll();
|
||||
m_backend.d.clear(&m_backend.d);
|
||||
m_backend.d.swap(&m_backend.d);
|
||||
m_backend.d.deinit(&m_backend.d);
|
||||
|
@ -232,8 +245,11 @@ void PainterGL::stop() {
|
|||
void PainterGL::pause() {
|
||||
m_active = false;
|
||||
// Make sure both buffers are filled
|
||||
m_gl->makeCurrent();
|
||||
dequeueAll();
|
||||
forceDraw();
|
||||
forceDraw();
|
||||
m_gl->doneCurrent();
|
||||
}
|
||||
|
||||
void PainterGL::unpause() {
|
||||
|
@ -250,3 +266,39 @@ void PainterGL::performDraw() {
|
|||
m_messagePainter->paint(&m_painter);
|
||||
}
|
||||
}
|
||||
|
||||
void PainterGL::enqueue(const uint32_t* backing) {
|
||||
m_mutex.lock();
|
||||
uint32_t* buffer;
|
||||
if (m_free.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
} else {
|
||||
buffer = m_free.takeLast();
|
||||
}
|
||||
memcpy(buffer, backing, 256 * VIDEO_VERTICAL_PIXELS * BYTES_PER_PIXEL);
|
||||
m_queue.enqueue(buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void PainterGL::dequeue() {
|
||||
m_mutex.lock();
|
||||
if (m_queue.isEmpty()) {
|
||||
m_mutex.unlock();
|
||||
return;
|
||||
}
|
||||
uint32_t* buffer = m_queue.dequeue();
|
||||
m_backend.d.postFrame(&m_backend.d, buffer);
|
||||
m_free.append(buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
||||
void PainterGL::dequeueAll() {
|
||||
uint32_t* buffer;
|
||||
m_mutex.lock();
|
||||
while (!m_queue.isEmpty()) {
|
||||
buffer = m_queue.dequeue();
|
||||
m_free.append(buffer);
|
||||
}
|
||||
m_backend.d.postFrame(&m_backend.d, buffer);
|
||||
m_mutex.unlock();
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
#include "Display.h"
|
||||
|
||||
#include <QGLWidget>
|
||||
#include <QList>
|
||||
#include <QMouseEvent>
|
||||
#include <QQueue>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
|
@ -74,12 +76,13 @@ Q_OBJECT
|
|||
|
||||
public:
|
||||
PainterGL(QGLWidget* parent);
|
||||
~PainterGL();
|
||||
|
||||
void setContext(GBAThread*);
|
||||
void setMessagePainter(MessagePainter*);
|
||||
void enqueue(const uint32_t* backing);
|
||||
|
||||
public slots:
|
||||
void setBacking(const uint32_t*);
|
||||
void forceDraw();
|
||||
void draw();
|
||||
void start();
|
||||
|
@ -92,8 +95,13 @@ public slots:
|
|||
|
||||
private:
|
||||
void performDraw();
|
||||
void dequeue();
|
||||
void dequeueAll();
|
||||
|
||||
QList<uint32_t*> m_free;
|
||||
QQueue<uint32_t*> m_queue;
|
||||
QPainter m_painter;
|
||||
QMutex m_mutex;
|
||||
QGLWidget* m_gl;
|
||||
bool m_active;
|
||||
GBAThread* m_context;
|
||||
|
|
|
@ -31,7 +31,8 @@ using namespace std;
|
|||
|
||||
GameController::GameController(QObject* parent)
|
||||
: QObject(parent)
|
||||
, m_drawContext(new uint32_t[256 * 256])
|
||||
, m_drawContext(new uint32_t[256 * VIDEO_HORIZONTAL_PIXELS])
|
||||
, m_frontBuffer(new uint32_t[256 * 256])
|
||||
, m_threadContext()
|
||||
, m_activeKeys(0)
|
||||
, m_inactiveKeys(0)
|
||||
|
@ -122,7 +123,8 @@ GameController::GameController(QObject* parent)
|
|||
m_threadContext.frameCallback = [](GBAThread* context) {
|
||||
GameController* controller = static_cast<GameController*>(context->userData);
|
||||
if (GBASyncDrawingFrame(&controller->m_threadContext.sync)) {
|
||||
controller->frameAvailable(controller->m_drawContext);
|
||||
memcpy(controller->m_frontBuffer, controller->m_drawContext, 256 * VIDEO_HORIZONTAL_PIXELS * BYTES_PER_PIXEL);
|
||||
controller->frameAvailable(controller->m_frontBuffer);
|
||||
} else {
|
||||
controller->frameAvailable(nullptr);
|
||||
}
|
||||
|
@ -216,6 +218,7 @@ GameController::~GameController() {
|
|||
GBACheatDeviceDestroy(&m_cheatDevice);
|
||||
delete m_renderer;
|
||||
delete[] m_drawContext;
|
||||
delete[] m_frontBuffer;
|
||||
delete m_backupLoadState;
|
||||
}
|
||||
|
||||
|
@ -339,7 +342,7 @@ void GameController::openGame(bool biosOnly) {
|
|||
}
|
||||
|
||||
m_inputController->recalibrateAxes();
|
||||
memset(m_drawContext, 0xF8, 1024 * 256);
|
||||
memset(m_drawContext, 0xF8, 1024 * VIDEO_HORIZONTAL_PIXELS);
|
||||
|
||||
if (!GBAThreadStart(&m_threadContext)) {
|
||||
m_gameOpen = false;
|
||||
|
|
|
@ -167,6 +167,7 @@ private:
|
|||
void enableTurbo();
|
||||
|
||||
uint32_t* m_drawContext;
|
||||
uint32_t* m_frontBuffer;
|
||||
GBAThread m_threadContext;
|
||||
GBAVideoSoftwareRenderer* m_renderer;
|
||||
GBACheatDevice m_cheatDevice;
|
||||
|
|
Loading…
Reference in New Issue