all repos — mgba @ e7028e4b296bdfdb6e484b9a116cd8fe9f66a11d

mGBA Game Boy Advance Emulator

src/platform/qt/VideoProxy.cpp (view raw)

  1/* Copyright (c) 2013-2018 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "VideoProxy.h"
  7
  8#include "CoreController.h"
  9
 10#include <QThread>
 11
 12using namespace QGBA;
 13
 14VideoProxy::VideoProxy() {
 15	mVideoLoggerRendererCreate(&m_logger.d, false);
 16	m_logger.d.block = true;
 17
 18	m_logger.d.init = &cbind<&VideoProxy::init>;
 19	m_logger.d.reset = &cbind<&VideoProxy::reset>;
 20	m_logger.d.deinit = &cbind<&VideoProxy::deinit>;
 21	m_logger.d.lock = &cbind<&VideoProxy::lock>;
 22	m_logger.d.unlock = &cbind<&VideoProxy::unlock>;
 23	m_logger.d.wait = &cbind<&VideoProxy::wait>;
 24	m_logger.d.wake = &callback<void, int>::func<&VideoProxy::wake>;
 25
 26	m_logger.d.writeData = &callback<bool, const void*, size_t>::func<&VideoProxy::writeData>;
 27	m_logger.d.readData = &callback<bool, void*, size_t, bool>::func<&VideoProxy::readData>;
 28	m_logger.d.postEvent = &callback<void, enum mVideoLoggerEvent>::func<&VideoProxy::postEvent>;
 29
 30	connect(this, &VideoProxy::dataAvailable, this, &VideoProxy::processData);
 31	connect(this, &VideoProxy::eventPosted, this, &VideoProxy::handleEvent);
 32}
 33
 34void VideoProxy::attach(CoreController* controller) {
 35	CoreController::Interrupter interrupter(controller);
 36	controller->thread()->core->videoLogger = &m_logger.d;
 37}
 38
 39void VideoProxy::processData() {
 40	mVideoLoggerRendererRun(&m_logger.d, false);
 41	m_fromThreadCond.wakeAll();
 42}
 43
 44void VideoProxy::init() {
 45	RingFIFOInit(&m_dirtyQueue, 0x80000);
 46}
 47
 48void VideoProxy::reset() {
 49	m_mutex.lock();
 50	RingFIFOClear(&m_dirtyQueue);
 51	m_toThreadCond.wakeAll();
 52	m_mutex.unlock();
 53}
 54
 55void VideoProxy::deinit() {
 56	RingFIFODeinit(&m_dirtyQueue);
 57}
 58
 59bool VideoProxy::writeData(const void* data, size_t length) {
 60	while (!RingFIFOWrite(&m_dirtyQueue, data, length)) {
 61		if (QThread::currentThread() == thread()) {
 62			// We're on the main thread
 63			mVideoLoggerRendererRun(&m_logger.d, false);
 64		} else {
 65			emit dataAvailable();
 66			m_mutex.lock();
 67			m_toThreadCond.wakeAll();
 68			m_fromThreadCond.wait(&m_mutex);
 69			m_mutex.unlock();
 70		}
 71	}
 72	return true;
 73}
 74
 75bool VideoProxy::readData(void* data, size_t length, bool block) {
 76	bool read = false;
 77	while (true) {
 78		read = RingFIFORead(&m_dirtyQueue, data, length);
 79		if (!block || read) {
 80			break;
 81		}
 82		m_mutex.lock();
 83		m_fromThreadCond.wakeAll();
 84		m_toThreadCond.wait(&m_mutex);
 85		m_mutex.unlock();
 86	}
 87	return read;
 88}
 89
 90void VideoProxy::postEvent(enum mVideoLoggerEvent event) {
 91	if (QThread::currentThread() == thread()) {
 92		// We're on the main thread
 93		emit eventPosted(event);
 94	} else {
 95		m_mutex.lock();
 96		emit eventPosted(event);
 97		m_fromThreadCond.wait(&m_mutex, 1);
 98		m_mutex.unlock();
 99	}
100}
101
102void VideoProxy::handleEvent(int event) {
103	m_mutex.lock();
104	m_logger.d.handleEvent(&m_logger.d, static_cast<enum mVideoLoggerEvent>(event));
105	m_fromThreadCond.wakeAll();
106	m_mutex.unlock();
107}
108
109void VideoProxy::lock() {
110	m_mutex.lock();
111}
112
113void VideoProxy::unlock() {
114	m_mutex.unlock();
115}
116
117void VideoProxy::wait() {
118	m_mutex.lock();
119	while (RingFIFOSize(&m_dirtyQueue)) {
120		if (QThread::currentThread() == thread()) {
121			// We're on the main thread
122			mVideoLoggerRendererRun(&m_logger.d, false);
123		} else {
124			emit dataAvailable();
125			m_toThreadCond.wakeAll();
126			m_fromThreadCond.wait(&m_mutex, 1);
127		}
128	}
129	m_mutex.unlock();
130}
131
132void VideoProxy::wake(int y) {
133	if ((y & 15) == 15) {
134		emit dataAvailable();
135		m_toThreadCond.wakeAll();
136	}
137}