all repos — mgba @ fc3e47a4bab1465b91e7368c6396b222f65f51cb

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	m_logger.d.waitOnFlush = false;
 18
 19	m_logger.d.init = &cbind<&VideoProxy::init>;
 20	m_logger.d.reset = &cbind<&VideoProxy::reset>;
 21	m_logger.d.deinit = &cbind<&VideoProxy::deinit>;
 22	m_logger.d.lock = &cbind<&VideoProxy::lock>;
 23	m_logger.d.unlock = &cbind<&VideoProxy::unlock>;
 24	m_logger.d.wait = &cbind<&VideoProxy::wait>;
 25	m_logger.d.wake = &callback<void, int>::func<&VideoProxy::wake>;
 26
 27	m_logger.d.writeData = &callback<bool, const void*, size_t>::func<&VideoProxy::writeData>;
 28	m_logger.d.readData = &callback<bool, void*, size_t, bool>::func<&VideoProxy::readData>;
 29	m_logger.d.postEvent = &callback<void, enum mVideoLoggerEvent>::func<&VideoProxy::postEvent>;
 30
 31	connect(this, &VideoProxy::dataAvailable, this, &VideoProxy::processData);
 32	connect(this, &VideoProxy::eventPosted, this, &VideoProxy::handleEvent);
 33}
 34
 35void VideoProxy::attach(CoreController* controller) {
 36	CoreController::Interrupter interrupter(controller);
 37	controller->thread()->core->videoLogger = &m_logger.d;
 38}
 39
 40void VideoProxy::detach(CoreController* controller) {
 41	CoreController::Interrupter interrupter(controller);
 42	if (controller->thread()->core->videoLogger == &m_logger.d) {
 43		controller->thread()->core->videoLogger = nullptr;
 44	}
 45}
 46
 47void VideoProxy::processData() {
 48	mVideoLoggerRendererRun(&m_logger.d, false);
 49	m_fromThreadCond.wakeAll();
 50}
 51
 52void VideoProxy::init() {
 53	RingFIFOInit(&m_dirtyQueue, 0x80000);
 54}
 55
 56void VideoProxy::reset() {
 57	m_mutex.lock();
 58	RingFIFOClear(&m_dirtyQueue);
 59	m_toThreadCond.wakeAll();
 60	m_mutex.unlock();
 61}
 62
 63void VideoProxy::deinit() {
 64	RingFIFODeinit(&m_dirtyQueue);
 65}
 66
 67bool VideoProxy::writeData(const void* data, size_t length) {
 68	while (!RingFIFOWrite(&m_dirtyQueue, data, length)) {
 69		if (QThread::currentThread() == thread()) {
 70			// We're on the main thread
 71			mVideoLoggerRendererRun(&m_logger.d, false);
 72		} else {
 73			emit dataAvailable();
 74			m_mutex.lock();
 75			m_toThreadCond.wakeAll();
 76			m_fromThreadCond.wait(&m_mutex);
 77			m_mutex.unlock();
 78		}
 79	}
 80	return true;
 81}
 82
 83bool VideoProxy::readData(void* data, size_t length, bool block) {
 84	bool read = false;
 85	while (true) {
 86		read = RingFIFORead(&m_dirtyQueue, data, length);
 87		if (!block || read) {
 88			break;
 89		}
 90		m_mutex.lock();
 91		m_fromThreadCond.wakeAll();
 92		m_toThreadCond.wait(&m_mutex);
 93		m_mutex.unlock();
 94	}
 95	return read;
 96}
 97
 98void VideoProxy::postEvent(enum mVideoLoggerEvent event) {
 99	if (QThread::currentThread() == thread()) {
100		// We're on the main thread
101		emit eventPosted(event);
102	} else {
103		m_mutex.lock();
104		emit eventPosted(event);
105		m_fromThreadCond.wait(&m_mutex, 1);
106		m_mutex.unlock();
107	}
108}
109
110void VideoProxy::handleEvent(int event) {
111	m_mutex.lock();
112	m_logger.d.handleEvent(&m_logger.d, static_cast<enum mVideoLoggerEvent>(event));
113	m_fromThreadCond.wakeAll();
114	m_mutex.unlock();
115}
116
117void VideoProxy::lock() {
118	m_mutex.lock();
119}
120
121void VideoProxy::unlock() {
122	m_mutex.unlock();
123}
124
125void VideoProxy::wait() {
126	m_mutex.lock();
127	while (RingFIFOSize(&m_dirtyQueue)) {
128		if (QThread::currentThread() == thread()) {
129			// We're on the main thread
130			mVideoLoggerRendererRun(&m_logger.d, false);
131		} else {
132			emit dataAvailable();
133			m_toThreadCond.wakeAll();
134			m_fromThreadCond.wait(&m_mutex, 1);
135		}
136	}
137	m_mutex.unlock();
138}
139
140void VideoProxy::wake(int y) {
141	if ((y & 15) == 15) {
142		emit dataAvailable();
143		m_toThreadCond.wakeAll();
144	}
145}