VIDEO: QTVR: Remove dependency on timer thread

Fixes concurrency issues and crashes in Gothos, related to accessing
OpenGL state outside of the main thread.
This commit is contained in:
Scott Percival
2025-09-11 23:17:34 +08:00
committed by Eugene Sandulenko
parent 2292c41abd
commit a6110de8a8
2 changed files with 22 additions and 46 deletions
+4 -2
View File
@@ -237,7 +237,6 @@ private:
float _fov = 56.0f;
float _hfov = 56.0f;
int _zoomState = kZoomNone;
bool _repeatTimerActive = false;
const PanoHotSpot *_rolloverHotspot = nullptr;
int _rolloverHotspotID = 0;
@@ -251,6 +250,9 @@ private:
bool _enableEditListBoundsCheckQuirk;
bool _cursorDirty;
Common::Point _cursorPos;
class VideoSampleDesc : public Common::QuickTimeParser::SampleDesc {
public:
VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag);
@@ -426,7 +428,7 @@ private:
// Current upscale level (0 or 1 or 2) of _upscaledConstructedPanorama compared to _constructedPano
// level 0 means that constructedPano was just contructed and hasn't been upscaled yet
// level 1 means only upscaled height (2x pixels)
// level 1 means only upscaled height (2x pixels)
// level 2 means upscaled height and width (4x pixels)
uint8 _upscaleLevel = 0;
+18 -44
View File
@@ -57,8 +57,6 @@ namespace Video {
static const char * const MACGUI_DATA_BUNDLE = "macgui.dat";
static void repeatCallback(void *data);
////////////////////////////////////////////
// QuickTimeDecoder methods related to QTVR
////////////////////////////////////////////
@@ -141,11 +139,6 @@ void QuickTimeDecoder::closeQTVR() {
delete _dataBundle;
_dataBundle = nullptr;
cleanupCursors();
if (_repeatTimerActive) {
_repeatTimerActive = false;
g_system->getTimerManager()->removeTimerProc(&repeatCallback);
}
}
void QuickTimeDecoder::renderHotspots(bool mode) {
@@ -663,6 +656,13 @@ const Graphics::Surface *QuickTimeDecoder::PanoTrackHandler::decodeNextFrame() {
if (!_isPanoConstructed)
return nullptr;
// inject fake key/mouse events if button is held down
if (_decoder->_isKeyDown)
_decoder->handleKey(_decoder->_lastKey, true, true);
if (_decoder->_isMouseButtonDown)
_decoder->handleMouseButton(true, _decoder->_prevMouse.x, _decoder->_prevMouse.y, true);
if (_dirty && _decoder->_transitionMode == kTransitionModeNormal) {
float quality = _decoder->getQuality();
float fov = _decoder->_fov;
@@ -699,6 +699,11 @@ const Graphics::Surface *QuickTimeDecoder::PanoTrackHandler::decodeNextFrame() {
swingTransitionHandler();
}
if (_decoder->_cursorDirty) {
_decoder->_cursorDirty = false;
_decoder->updateQTVRCursor(_decoder->_cursorPos.x, _decoder->_cursorPos.y);
}
return _projectedPano;
}
@@ -1510,10 +1515,6 @@ void QuickTimeDecoder::setClickedHotSpot(int id) {
//////////////////////////////
void QuickTimeDecoder::handleQuit() {
if (_repeatTimerActive) {
_repeatTimerActive = false;
g_system->getTimerManager()->removeTimerProc(&repeatCallback);
}
}
void QuickTimeDecoder::handleMouseMove(int16 x, int16 y) {
@@ -1522,7 +1523,8 @@ void QuickTimeDecoder::handleMouseMove(int16 x, int16 y) {
else if (_qtvrType == QTVRType::PANORAMA)
handlePanoMouseMove(x, y);
updateQTVRCursor(x, y);
_cursorDirty = true;
_cursorPos = Common::Point(x, y);
}
void QuickTimeDecoder::handleObjectMouseMove(int16 x, int16 y) {
@@ -1577,36 +1579,14 @@ void QuickTimeDecoder::handlePanoMouseMove(int16 x, int16 y) {
lookupHotspot(x, y);
}
#define REPEAT_DELAY 30000
static void repeatCallback(void *data) {
QuickTimeDecoder *decoder = (QuickTimeDecoder *)data;
if (decoder->_isKeyDown)
decoder->handleKey(decoder->_lastKey, true, true);
if (decoder->_isMouseButtonDown)
decoder->handleMouseButton(true, decoder->_prevMouse.x, decoder->_prevMouse.y, true);
}
void QuickTimeDecoder::handleMouseButton(bool isDown, int16 x, int16 y, bool repeat) {
if (_qtvrType == QTVRType::OBJECT)
handleObjectMouseButton(isDown, x, y, repeat);
else if (_qtvrType == QTVRType::PANORAMA)
handlePanoMouseButton(isDown, x, y, repeat);
if (isDown) {
if (!_repeatTimerActive)
g_system->getTimerManager()->installTimerProc(&repeatCallback, REPEAT_DELAY, this, "Mouse Repeat Handler");
_repeatTimerActive = true;
} else {
if (_repeatTimerActive) {
_repeatTimerActive = false;
g_system->getTimerManager()->removeTimerProc(&repeatCallback);
}
}
updateQTVRCursor(x, y);
_cursorDirty = true;
_cursorPos = Common::Point(x, y);
}
void QuickTimeDecoder::handleObjectMouseButton(bool isDown, int16 x, int16 y, bool repeat) {
@@ -1699,18 +1679,12 @@ void QuickTimeDecoder::handleKey(Common::KeyState &state, bool down, bool repeat
if (down) {
_lastKey = state;
_isKeyDown = true;
if (!_repeatTimerActive)
g_system->getTimerManager()->installTimerProc(&repeatCallback, REPEAT_DELAY, this, "Keyboard Repeat Handler");
_repeatTimerActive = true;
} else {
_isKeyDown = false;
if (_repeatTimerActive) {
_repeatTimerActive = false;
g_system->getTimerManager()->removeTimerProc(&repeatCallback);
}
}
updateQTVRCursor(_prevMouse.x, _prevMouse.y);
_cursorDirty = true;
_cursorPos = Common::Point(_prevMouse.x, _prevMouse.y);
}
void QuickTimeDecoder::handleObjectKey(Common::KeyState &state, bool down, bool repeat) {