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