Qt: Fix sync, hopefully

This commit is contained in:
Jeffrey Pfau 2015-08-06 19:04:03 -07:00
parent 581d5fab3b
commit 870c8ebb8c
5 changed files with 80 additions and 15 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -167,6 +167,7 @@ private:
void enableTurbo();
uint32_t* m_drawContext;
uint32_t* m_frontBuffer;
GBAThread m_threadContext;
GBAVideoSoftwareRenderer* m_renderer;
GBACheatDevice m_cheatDevice;