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); setAcceptDrops(true);
gameTimer = new QTimer( this ); 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); emulatorThread = new emulatorThread_t(this);
connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater); connect(emulatorThread, &QThread::finished, emulatorThread, &QObject::deleteLater);
@ -336,8 +331,6 @@ consoleWin_t::~consoleWin_t(void)
unloadVideoDriver(); unloadVideoDriver();
delete mutex;
// LoadGame() checks for an IP and if it finds one begins a network session // LoadGame() checks for an IP and if it finds one begins a network session
// clear the NetworkIP field so this doesn't happen unintentionally // clear the NetworkIP field so this doesn't happen unintentionally
//g_config->setOption ("SDL.NetworkIP", ""); //g_config->setOption ("SDL.NetworkIP", "");
@ -4564,17 +4557,28 @@ int consoleWin_t::getPeriodicInterval(void)
void consoleWin_t::transferVideoBuffer(void) void consoleWin_t::transferVideoBuffer(void)
{ {
bool redraw = false;
FCEU_PROFILE_FUNC(prof, "VideoXfer"); 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(); nes_shm->blitUpdated = 0;
viewport_Interface->queueRedraw();
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) void consoleWin_t::emuFrameFinish(void)

View File

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

View File

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

View File

@ -496,8 +496,6 @@ doBlitScreen(uint8_t *XBuf, uint8_t *dest)
void void
BlitScreen(uint8 *XBuf) BlitScreen(uint8 *XBuf)
{ {
int i = nes_shm->pixBufIdx;
if (usePaletteForVideoBg) if (usePaletteForVideoBg)
{ {
unsigned char r, g, b; 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; int i = nes_shm->pixBufIdx;
nes_shm->blit_count++;
nes_shm->blitUpdated = 1; 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) void FCEUI_AviVideoUpdate(const unsigned char* buffer)

View File

@ -48,6 +48,24 @@ void mutex::unlock(void)
#endif #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 // Scoped AutoLock
//----------------------------------------------------- //-----------------------------------------------------

View File

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