SKY: get rid of timer based gfx updates

on most platforms timers are implemented using threads. never ever make
gfx updates from another thread other than the main one. seriously.
replace the whole timer crap in sky with timestamp based updates.
this fixes crashes when OpenGL is enabled (android included).

needs more testing.
This commit is contained in:
dhewg 2011-02-14 01:12:40 +01:00
parent 1e989c44ed
commit f621f6a505
5 changed files with 65 additions and 49 deletions

View file

@ -644,6 +644,7 @@ Intro::Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *t
Intro::~Intro() { Intro::~Intro() {
if (_skyScreen->sequenceRunning()) if (_skyScreen->sequenceRunning())
_skyScreen->stopSequence(); _skyScreen->stopSequence();
free(_textBuf); free(_textBuf);
free(_saveBuf); free(_saveBuf);
free(_bgBuf); free(_bgBuf);
@ -658,6 +659,7 @@ bool Intro::doIntro(bool floppyIntro) {
if (!escDelay(3000)) if (!escDelay(3000))
return false; return false;
if (floppyIntro) if (floppyIntro)
_skyMusic->startMusic(1); _skyMusic->startMusic(1);
@ -817,6 +819,7 @@ bool Intro::floppyScrollFlirt() {
bool Intro::commandFlirt(uint16 *&data) { bool Intro::commandFlirt(uint16 *&data) {
_skyScreen->startSequence(*data++); _skyScreen->startSequence(*data++);
while ((*data != COMMANDEND) || _skyScreen->sequenceRunning()) { while ((*data != COMMANDEND) || _skyScreen->sequenceRunning()) {
while ((_skyScreen->seqFramesLeft() < *data)) { while ((_skyScreen->seqFramesLeft() < *data)) {
data++; data++;
@ -844,11 +847,13 @@ bool Intro::commandFlirt(uint16 *&data) {
error("Unknown FLIRT command %X", command); error("Unknown FLIRT command %X", command);
} }
} }
if (!escDelay(50)) { if (!escDelay(50)) {
_skyScreen->stopSequence(); _skyScreen->stopSequence();
return false; return false;
} }
} }
data++; // move pointer over "COMMANDEND" data++; // move pointer over "COMMANDEND"
return true; return true;
} }
@ -893,6 +898,7 @@ void Intro::restoreScreen() {
bool Intro::escDelay(uint32 msecs) { bool Intro::escDelay(uint32 msecs) {
Common::EventManager *eventMan = _system->getEventManager(); Common::EventManager *eventMan = _system->getEventManager();
Common::Event event; Common::Event event;
if (_relDelay == 0) // first call, init with system time if (_relDelay == 0) // first call, init with system time
_relDelay = (int32)_system->getMillis(); _relDelay = (int32)_system->getMillis();
@ -911,11 +917,13 @@ bool Intro::escDelay(uint32 msecs) {
nDelay = _relDelay - _system->getMillis(); nDelay = _relDelay - _system->getMillis();
if (nDelay < 0) if (nDelay < 0)
nDelay = 0; nDelay = 0;
else if (nDelay > 40) else if (nDelay > 10)
nDelay = 40; nDelay = 10;
_system->delayMillis(nDelay); _system->delayMillis(nDelay);
_skyScreen->processSequence();
_system->updateScreen(); _system->updateScreen();
} while (nDelay == 40); } while (nDelay == 10);
return true; return true;
} }

View file

@ -86,7 +86,7 @@ Screen::Screen(OSystem *pSystem, Disk *pDisk, SkyCompact *skyCompact) {
_system->getPaletteManager()->setPalette(tmpPal, 0, VGA_COLOURS); _system->getPaletteManager()->setPalette(tmpPal, 0, VGA_COLOURS);
_currentPalette = 0; _currentPalette = 0;
_seqInfo.framesLeft = 0; _seqInfo.nextFrame = _seqInfo.framesLeft = 0;
_seqInfo.seqData = _seqInfo.seqDataPos = NULL; _seqInfo.seqData = _seqInfo.seqDataPos = NULL;
_seqInfo.running = false; _seqInfo.running = false;
} }
@ -348,7 +348,7 @@ void Screen::fnFadeUp(uint32 palNum, uint32 scroll) {
scrOldPtr += GAME_SCREEN_WIDTH; scrOldPtr += GAME_SCREEN_WIDTH;
} }
showScreen(_scrollScreen); showScreen(_scrollScreen);
waitForTimer(); waitForTick();
} }
showScreen(_currentScreen); showScreen(_currentScreen);
} else if (scroll == 321) { // scroll right (going left) } else if (scroll == 321) { // scroll right (going left)
@ -364,7 +364,7 @@ void Screen::fnFadeUp(uint32 palNum, uint32 scroll) {
scrOldPtr += GAME_SCREEN_WIDTH; scrOldPtr += GAME_SCREEN_WIDTH;
} }
showScreen(_scrollScreen); showScreen(_scrollScreen);
waitForTimer(); waitForTick();
} }
showScreen(_currentScreen); showScreen(_currentScreen);
} }
@ -374,37 +374,49 @@ void Screen::fnFadeUp(uint32 palNum, uint32 scroll) {
} }
} }
void Screen::waitForTimer() { void Screen::waitForTick() {
uint32 start = _system->getMillis();
uint32 end = start + 20 - (start % 20);
uint32 remain;
Common::EventManager *eventMan = _system->getEventManager(); Common::EventManager *eventMan = _system->getEventManager();
_gotTick = false;
while (!_gotTick) {
Common::Event event; Common::Event event;
while (true) {
start = _system->getMillis();
if (start >= end)
return;
while (eventMan->pollEvent(event))
;
remain = end - start;
if (remain < 10) {
_system->delayMillis(remain);
return;
}
_system->delayMillis(10);
}
}
void Screen::waitForSequence() {
Common::EventManager *eventMan = _system->getEventManager();
Common::Event event;
while (_seqInfo.running) {
processSequence();
_system->delayMillis(10); _system->delayMillis(10);
while (eventMan->pollEvent(event)) while (eventMan->pollEvent(event))
; ;
} }
} }
void Screen::waitForSequence() {
Common::EventManager *eventMan = _system->getEventManager();
while (_seqInfo.running) {
Common::Event event;
_system->delayMillis(20);
while (eventMan->pollEvent(event))
;
}
}
void Screen::handleTimer() {
_gotTick = true;
if (_seqInfo.running)
processSequence();
}
void Screen::startSequence(uint16 fileNum) { void Screen::startSequence(uint16 fileNum) {
_seqInfo.seqData = _skyDisk->loadFile(fileNum); _seqInfo.seqData = _skyDisk->loadFile(fileNum);
_seqInfo.nextFrame = _system->getMillis();
_seqInfo.framesLeft = _seqInfo.seqData[0]; _seqInfo.framesLeft = _seqInfo.seqData[0];
_seqInfo.seqDataPos = _seqInfo.seqData + 1; _seqInfo.seqDataPos = _seqInfo.seqData + 1;
_seqInfo.delay = SEQ_DELAY; _seqInfo.delay = SEQ_DELAY;
@ -414,6 +426,7 @@ void Screen::startSequence(uint16 fileNum) {
void Screen::startSequenceItem(uint16 itemNum) { void Screen::startSequenceItem(uint16 itemNum) {
_seqInfo.seqData = (uint8 *)SkyEngine::fetchItem(itemNum); _seqInfo.seqData = (uint8 *)SkyEngine::fetchItem(itemNum);
_seqInfo.nextFrame = _system->getMillis();
_seqInfo.framesLeft = _seqInfo.seqData[0] - 1; _seqInfo.framesLeft = _seqInfo.seqData[0] - 1;
_seqInfo.seqDataPos = _seqInfo.seqData + 1; _seqInfo.seqDataPos = _seqInfo.seqData + 1;
_seqInfo.delay = SEQ_DELAY; _seqInfo.delay = SEQ_DELAY;
@ -423,21 +436,29 @@ void Screen::startSequenceItem(uint16 itemNum) {
void Screen::stopSequence() { void Screen::stopSequence() {
_seqInfo.running = false; _seqInfo.running = false;
waitForTimer(); waitForTick();
waitForTimer(); waitForTick();
_seqInfo.framesLeft = 0; _seqInfo.nextFrame = _seqInfo.framesLeft = 0;
free(_seqInfo.seqData); free(_seqInfo.seqData);
_seqInfo.seqData = _seqInfo.seqDataPos = NULL; _seqInfo.seqData = _seqInfo.seqDataPos = NULL;
} }
void Screen::processSequence() { void Screen::processSequence() {
uint32 screenPos = 0; if (!_seqInfo.running)
return;
if (_system->getMillis() < _seqInfo.nextFrame)
return;
_seqInfo.delay--; _seqInfo.delay--;
if (_seqInfo.delay == 0) { if (_seqInfo.delay == 0) {
_seqInfo.delay = SEQ_DELAY; _seqInfo.delay = SEQ_DELAY;
_seqInfo.nextFrame += 20 * SEQ_DELAY;
memset(_seqGrid, 0, 12 * 20); memset(_seqGrid, 0, 12 * 20);
uint32 screenPos = 0;
uint8 nrToSkip, nrToDo, cnt; uint8 nrToSkip, nrToDo, cnt;
do { do {
do { do {
@ -445,6 +466,7 @@ void Screen::processSequence() {
_seqInfo.seqDataPos++; _seqInfo.seqDataPos++;
screenPos += nrToSkip; screenPos += nrToSkip;
} while (nrToSkip == 0xFF); } while (nrToSkip == 0xFF);
do { do {
nrToDo = _seqInfo.seqDataPos[0]; nrToDo = _seqInfo.seqDataPos[0];
_seqInfo.seqDataPos++; _seqInfo.seqDataPos++;

View file

@ -75,6 +75,7 @@ public:
void startSequenceItem(uint16 itemNum); void startSequenceItem(uint16 itemNum);
void stopSequence(); void stopSequence();
bool sequenceRunning() { return _seqInfo.running; } bool sequenceRunning() { return _seqInfo.running; }
void processSequence();
void waitForSequence(); void waitForSequence();
uint32 seqFramesLeft() { return _seqInfo.framesLeft; } uint32 seqFramesLeft() { return _seqInfo.framesLeft; }
uint8 *giveCurrent() { return _currentScreen; } uint8 *giveCurrent() { return _currentScreen; }
@ -105,14 +106,13 @@ private:
uint32 _currentPalette; uint32 _currentPalette;
uint8 _seqGrid[20 * 12]; uint8 _seqGrid[20 * 12];
bool volatile _gotTick; void waitForTick();
void waitForTimer();
void processSequence();
uint8 *_gameGrid; uint8 *_gameGrid;
uint8 *_currentScreen; uint8 *_currentScreen;
uint8 *_scrollScreen; uint8 *_scrollScreen;
struct { struct {
uint32 nextFrame;
uint32 framesLeft; uint32 framesLeft;
uint32 delay; uint32 delay;
uint8 *seqData; uint8 *seqData;

View file

@ -84,8 +84,6 @@ SkyEngine::SkyEngine(OSystem *syst)
} }
SkyEngine::~SkyEngine() { SkyEngine::~SkyEngine() {
_timer->removeTimerProc(&timerHandler);
delete _skyLogic; delete _skyLogic;
delete _skySound; delete _skySound;
delete _skyMusic; delete _skyMusic;
@ -207,6 +205,7 @@ Common::Error SkyEngine::go() {
} }
_skyLogic->engine(); _skyLogic->engine();
_skyScreen->processSequence();
_skyScreen->recreate(); _skyScreen->recreate();
_skyScreen->spriteEngine(); _skyScreen->spriteEngine();
if (_debugger->showGrid()) { if (_debugger->showGrid()) {
@ -300,9 +299,6 @@ Common::Error SkyEngine::init() {
_skyLogic = new Logic(_skyCompact, _skyScreen, _skyDisk, _skyText, _skyMusic, _skyMouse, _skySound); _skyLogic = new Logic(_skyCompact, _skyScreen, _skyDisk, _skyText, _skyMusic, _skyMouse, _skySound);
_skyMouse->useLogicInstance(_skyLogic); _skyMouse->useLogicInstance(_skyLogic);
// initialize timer *after* _skyScreen has been initialized.
_timer->installTimerProc(&timerHandler, 1000000 / 50, this); //call 50 times per second
_skyControl = new Control(_saveFileMan, _skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _skySound, _skyCompact, _system); _skyControl = new Control(_saveFileMan, _skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _skySound, _skyCompact, _system);
_skyLogic->useControlInstance(_skyControl); _skyLogic->useControlInstance(_skyControl);
@ -386,14 +382,6 @@ void *SkyEngine::fetchItem(uint32 num) {
return _itemList[num]; return _itemList[num];
} }
void SkyEngine::timerHandler(void *refCon) {
((SkyEngine *)refCon)->gotTimerTick();
}
void SkyEngine::gotTimerTick() {
_skyScreen->handleTimer();
}
void SkyEngine::delay(int32 amount) { void SkyEngine::delay(int32 amount) {
Common::Event event; Common::Event event;

View file

@ -121,8 +121,6 @@ protected:
void initItemList(); void initItemList();
void initVirgin(); void initVirgin();
static void timerHandler(void *ptr);
void gotTimerTick();
void loadFixedItems(); void loadFixedItems();
}; };