For Qt GUI, add video buffer mutex to ensure clean transfer between emulation and GUI threads. Use common FCEU::mutex wrapper for cleaner code.

This commit is contained in:
harry 2024-01-31 05:28:41 -05:00
parent cb0edc5a21
commit d363d04dbb
6 changed files with 54 additions and 27 deletions

View File

@ -170,11 +170,6 @@ consoleWin_t::consoleWin_t(QWidget *parent)
setAcceptDrops(true);
gameTimer = new QTimer( this );
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
mutex = new QRecursiveMutex();
#else
mutex = new QMutex( QMutex::Recursive );
#endif
emulatorThread = new emulatorThread_t(this);
connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater);
@ -336,8 +331,6 @@ consoleWin_t::~consoleWin_t(void)
unloadVideoDriver();
delete mutex;
// LoadGame() checks for an IP and if it finds one begins a network session
// clear the NetworkIP field so this doesn't happen unintentionally
//g_config->setOption ("SDL.NetworkIP", "");
@ -4564,17 +4557,28 @@ int consoleWin_t::getPeriodicInterval(void)
void consoleWin_t::transferVideoBuffer(void)
{
bool redraw = false;
FCEU_PROFILE_FUNC(prof, "VideoXfer");
if ( nes_shm->blitUpdated )
{
nes_shm->blitUpdated = 0;
if (viewport_Interface)
{
FCEU::autoScopedLock lock(videoBufferMutex);
if ( nes_shm->blitUpdated )
{
viewport_Interface->transfer2LocalBuffer();
viewport_Interface->queueRedraw();
nes_shm->blitUpdated = 0;
if (viewport_Interface != nullptr)
{
viewport_Interface->transfer2LocalBuffer();
redraw = true;
}
}
}
// Don't queue redraw in mutex lock scope
if (redraw && (viewport_Interface != nullptr))
{
viewport_Interface->queueRedraw();
}
}
void consoleWin_t::emuFrameFinish(void)

View File

@ -27,6 +27,7 @@
#include <QRecursiveMutex>
#endif
#include "utils/mutex.h"
#include "Qt/ColorMenu.h"
#include "Qt/ConsoleViewerGL.h"
#include "Qt/ConsoleViewerSDL.h"
@ -134,11 +135,8 @@ class consoleWin_t : public QMainWindow
void setCyclePeriodms( int ms );
#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
QRecursiveMutex *mutex;
#else
QMutex *mutex;
#endif
FCEU::mutex emulatorMutex;
FCEU::mutex videoBufferMutex;
int videoInit(void);
void videoReset(void);

View File

@ -1382,7 +1382,7 @@ void fceuWrapperLock(void)
mutexPending++;
if ( consoleWindow != NULL )
{
consoleWindow->mutex->lock();
consoleWindow->emulatorMutex.lock();
}
mutexPending--;
mutexLocks++;
@ -1412,7 +1412,7 @@ bool fceuWrapperTryLock(int timeout)
mutexPending++;
if ( consoleWindow != NULL )
{
lockAcq = consoleWindow->mutex->tryLock( timeout );
lockAcq = consoleWindow->emulatorMutex.tryLock( timeout );
}
mutexPending--;
@ -1430,7 +1430,7 @@ void fceuWrapperUnLock(void)
mutexLocks--;
if ( consoleWindow != NULL )
{
consoleWindow->mutex->unlock();
consoleWindow->emulatorMutex.unlock();
}
}
else

View File

@ -496,8 +496,6 @@ doBlitScreen(uint8_t *XBuf, uint8_t *dest)
void
BlitScreen(uint8 *XBuf)
{
int i = nes_shm->pixBufIdx;
if (usePaletteForVideoBg)
{
unsigned char r, g, b;
@ -511,11 +509,18 @@ BlitScreen(uint8 *XBuf)
}
}
doBlitScreen(XBuf, (uint8_t*)nes_shm->pixbuf[i]);
if (consoleWindow != nullptr)
{
FCEU::autoScopedLock lock(consoleWindow->videoBufferMutex);
nes_shm->pixBufIdx = (i+1) % NES_VIDEO_BUFLEN;
nes_shm->blit_count++;
nes_shm->blitUpdated = 1;
int i = nes_shm->pixBufIdx;
doBlitScreen(XBuf, (uint8_t*)nes_shm->pixbuf[i]);
nes_shm->pixBufIdx = (i+1) % NES_VIDEO_BUFLEN;
nes_shm->blit_count++;
nes_shm->blitUpdated = 1;
}
}
void FCEUI_AviVideoUpdate(const unsigned char* buffer)

View File

@ -48,6 +48,24 @@ void mutex::unlock(void)
#endif
}
bool mutex::tryLock()
{
bool success = false;
#ifdef __QT_DRIVER__
success = mtx->tryLock();
#endif
return success;
}
bool mutex::tryLock(int timeout)
{
bool success = false;
#ifdef __QT_DRIVER__
success = mtx->tryLock(timeout);
#endif
return success;
}
//-----------------------------------------------------
// Scoped AutoLock
//-----------------------------------------------------

View File

@ -18,6 +18,8 @@ namespace FCEU
void lock(void);
void unlock(void);
bool tryLock(void);
bool tryLock(int timeout);
private:
#ifdef __QT_DRIVER__