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