diff --git a/include/mgba/feature/thread-proxy.h b/include/mgba/feature/thread-proxy.h index cb663d506..36f432b03 100644 --- a/include/mgba/feature/thread-proxy.h +++ b/include/mgba/feature/thread-proxy.h @@ -29,6 +29,7 @@ struct mVideoThreadProxy { Condition toThreadCond; Mutex mutex; enum mVideoThreadProxyState threadState; + enum mVideoLoggerEvent event; struct RingFIFO dirtyQueue; }; diff --git a/include/mgba/feature/video-logger.h b/include/mgba/feature/video-logger.h index f194433a2..bae94157a 100644 --- a/include/mgba/feature/video-logger.h +++ b/include/mgba/feature/video-logger.h @@ -27,6 +27,13 @@ enum mVideoLoggerDirtyType { DIRTY_BUFFER, }; +enum mVideoLoggerEvent { + LOGGER_EVENT_NONE = 0, + LOGGER_EVENT_INIT, + LOGGER_EVENT_DEINIT, + LOGGER_EVENT_RESET, +}; + struct mVideoLoggerDirtyInfo { enum mVideoLoggerDirtyType type; uint32_t address; @@ -38,6 +45,7 @@ struct VFile; struct mVideoLogger { bool (*writeData)(struct mVideoLogger* logger, const void* data, size_t length); bool (*readData)(struct mVideoLogger* logger, void* data, size_t length, bool block); + void (*postEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); void* dataContext; bool block; @@ -52,6 +60,7 @@ struct mVideoLogger { void* context; bool (*parsePacket)(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet); + void (*handleEvent)(struct mVideoLogger* logger, enum mVideoLoggerEvent event); uint16_t* (*vramBlock)(struct mVideoLogger* logger, uint32_t address); size_t vramSize; diff --git a/src/feature/thread-proxy.c b/src/feature/thread-proxy.c index d00da8cd8..7a67dbedd 100644 --- a/src/feature/thread-proxy.c +++ b/src/feature/thread-proxy.c @@ -18,6 +18,7 @@ static THREAD_ENTRY _proxyThread(void* renderer); static bool _writeData(struct mVideoLogger* logger, const void* data, size_t length); static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bool block); +static void _postEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent); static void _lock(struct mVideoLogger* logger); static void _unlock(struct mVideoLogger* logger); @@ -38,6 +39,7 @@ void mVideoThreadProxyCreate(struct mVideoThreadProxy* renderer) { renderer->d.writeData = _writeData; renderer->d.readData = _readData; + renderer->d.postEvent = _postEvent; } void mVideoThreadProxyInit(struct mVideoLogger* logger) { @@ -131,6 +133,14 @@ static bool _readData(struct mVideoLogger* logger, void* data, size_t length, bo return read; } +static void _postEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) { + struct mVideoThreadProxy* proxyRenderer = (struct mVideoThreadProxy*) logger; + MutexLock(&proxyRenderer->mutex); + proxyRenderer->event = event; + ConditionWake(&proxyRenderer->toThreadCond); + MutexUnlock(&proxyRenderer->mutex); +} + static void _lock(struct mVideoLogger* logger) { struct mVideoThreadProxy* proxyRenderer = (struct mVideoThreadProxy*) logger; MutexLock(&proxyRenderer->mutex); @@ -172,13 +182,18 @@ static THREAD_ENTRY _proxyThread(void* logger) { break; } proxyRenderer->threadState = PROXY_THREAD_BUSY; - MutexUnlock(&proxyRenderer->mutex); - if (!mVideoLoggerRendererRun(&proxyRenderer->d, false)) { - // FIFO was corrupted - proxyRenderer->threadState = PROXY_THREAD_STOPPED; - mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); + if (proxyRenderer->event) { + proxyRenderer->d.handleEvent(&proxyRenderer->d, proxyRenderer->event); + proxyRenderer->event = 0; + } else { + MutexUnlock(&proxyRenderer->mutex); + if (!mVideoLoggerRendererRun(&proxyRenderer->d, false)) { + // FIFO was corrupted + proxyRenderer->threadState = PROXY_THREAD_STOPPED; + mLOG(GBA_VIDEO, ERROR, "Proxy thread queue got corrupted!"); + } + MutexLock(&proxyRenderer->mutex); } - MutexLock(&proxyRenderer->mutex); ConditionWake(&proxyRenderer->fromThreadCond); if (proxyRenderer->threadState != PROXY_THREAD_STOPPED) { proxyRenderer->threadState = PROXY_THREAD_IDLE; diff --git a/src/gba/extra/proxy.c b/src/gba/extra/proxy.c index deeec5603..ea884db3b 100644 --- a/src/gba/extra/proxy.c +++ b/src/gba/extra/proxy.c @@ -21,6 +21,7 @@ static void GBAVideoProxyRendererFinishFrame(struct GBAVideoRenderer* renderer); static void GBAVideoProxyRendererGetPixels(struct GBAVideoRenderer* renderer, size_t* stride, const void** pixels); static void GBAVideoProxyRendererPutPixels(struct GBAVideoRenderer* renderer, size_t stride, const void* pixels); +static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event); static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* packet); static uint16_t* _vramBlock(struct mVideoLogger* logger, uint32_t address); @@ -45,6 +46,7 @@ void GBAVideoProxyRendererCreate(struct GBAVideoProxyRenderer* renderer, struct renderer->logger->context = renderer; renderer->logger->parsePacket = _parsePacket; + renderer->logger->handleEvent = _handleEvent; renderer->logger->vramBlock = _vramBlock; renderer->logger->paletteSize = SIZE_PALETTE_RAM; renderer->logger->vramSize = SIZE_VRAM; @@ -105,7 +107,11 @@ void GBAVideoProxyRendererInit(struct GBAVideoRenderer* renderer) { _init(proxyRenderer); _reset(proxyRenderer); - proxyRenderer->backend->init(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->init(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_INIT); + } } void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) { @@ -113,17 +119,42 @@ void GBAVideoProxyRendererReset(struct GBAVideoRenderer* renderer) { _reset(proxyRenderer); - proxyRenderer->backend->reset(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->reset(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_RESET); + } } void GBAVideoProxyRendererDeinit(struct GBAVideoRenderer* renderer) { struct GBAVideoProxyRenderer* proxyRenderer = (struct GBAVideoProxyRenderer*) renderer; - proxyRenderer->backend->deinit(proxyRenderer->backend); + if (!proxyRenderer->logger->block) { + proxyRenderer->backend->deinit(proxyRenderer->backend); + } else { + proxyRenderer->logger->postEvent(proxyRenderer->logger, LOGGER_EVENT_DEINIT); + } mVideoLoggerRendererDeinit(proxyRenderer->logger); } +static void _handleEvent(struct mVideoLogger* logger, enum mVideoLoggerEvent event) { + struct GBAVideoProxyRenderer* proxyRenderer = logger->context; + switch (event) { + default: + break; + case LOGGER_EVENT_INIT: + proxyRenderer->backend->init(proxyRenderer->backend); + break; + case LOGGER_EVENT_DEINIT: + proxyRenderer->backend->deinit(proxyRenderer->backend); + break; + case LOGGER_EVENT_RESET: + proxyRenderer->backend->reset(proxyRenderer->backend); + break; + } +} + static bool _parsePacket(struct mVideoLogger* logger, const struct mVideoLoggerDirtyInfo* item) { struct GBAVideoProxyRenderer* proxyRenderer = logger->context; switch (item->type) { diff --git a/src/platform/qt/DisplayGL.cpp b/src/platform/qt/DisplayGL.cpp index b7af84b25..c7374f274 100644 --- a/src/platform/qt/DisplayGL.cpp +++ b/src/platform/qt/DisplayGL.cpp @@ -40,6 +40,7 @@ DisplayGL::DisplayGL(const QGLFormat& format, QWidget* parent) setUpdatesEnabled(false); // Prevent paint events, which can cause race conditions connect(&m_videoProxy, &VideoProxy::dataAvailable, &m_videoProxy, &VideoProxy::processData); + connect(&m_videoProxy, &VideoProxy::eventPosted, &m_videoProxy, &VideoProxy::handleEvent); } DisplayGL::~DisplayGL() { diff --git a/src/platform/qt/VideoProxy.cpp b/src/platform/qt/VideoProxy.cpp index 0c378f59c..a6c673207 100644 --- a/src/platform/qt/VideoProxy.cpp +++ b/src/platform/qt/VideoProxy.cpp @@ -23,6 +23,7 @@ VideoProxy::VideoProxy() { m_logger.d.writeData = &callback::func<&VideoProxy::writeData>; m_logger.d.readData = &callback::func<&VideoProxy::readData>; + m_logger.d.postEvent = &callback::func<&VideoProxy::postEvent>; } void VideoProxy::attach(CoreController* controller) { @@ -74,6 +75,14 @@ bool VideoProxy::readData(void* data, size_t length, bool block) { return read; } +void VideoProxy::postEvent(enum mVideoLoggerEvent event) { + emit eventPosted(event); +} + +void VideoProxy::handleEvent(int event) { + m_logger.d.handleEvent(&m_logger.d, static_cast(event)); +} + void VideoProxy::lock() { m_mutex.lock(); } diff --git a/src/platform/qt/VideoProxy.h b/src/platform/qt/VideoProxy.h index d686478c0..7f778a605 100644 --- a/src/platform/qt/VideoProxy.h +++ b/src/platform/qt/VideoProxy.h @@ -26,9 +26,11 @@ public: signals: void dataAvailable(); + void eventPosted(int); public slots: void processData(); + void handleEvent(int); private: void init(); @@ -37,6 +39,7 @@ private: bool writeData(const void* data, size_t length); bool readData(void* data, size_t length, bool block); + void postEvent(enum mVideoLoggerEvent event); void lock(); void unlock();