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}