KYRA: implement idle screen updates

Apparently, as I have been told, there are (still) OS'es with non-compositing window managers which may cause glitches when drawing windows over the ScummVM window, unless the engine keeps updating the screen. So, now we do that, even if there isn't any actual on-screen activity. The whole thing is a bit more tricky than it would appear at first glance, since one misplaced/untimely screen update may cause palette glitches. I have implemented a timer which is reset whenever actual on-screen activity happens. That should work around any such glitches.

Maybe the rates for the timer have to be tweaked some more. I have also added an ifdef so this could be disabled or restricted to certain platforms if required.
This commit is contained in:
athrxx 2021-12-05 02:11:23 +01:00
parent 02bd4e46a3
commit 9673b0a0ea
12 changed files with 46 additions and 22 deletions

View File

@ -1664,7 +1664,7 @@ void KyraEngine_HoF::cauldronItemAnim(int item) {
mouseY -= 2;
uint32 waitEnd = _system->getMillis() + _tickLength;
setMousePos(mouseX, mouseY);
_system->updateScreen();
_screen->updateBackendScreen(true);
delayUntil(waitEnd);
}
@ -1675,7 +1675,7 @@ void KyraEngine_HoF::cauldronItemAnim(int item) {
mouseX -= 2;
uint32 waitEnd = _system->getMillis() + _tickLength;
setMousePos(mouseX, mouseY);
_system->updateScreen();
_screen->updateBackendScreen(true);
delayUntil(waitEnd);
}

View File

@ -475,8 +475,7 @@ void KyraEngine_v1::updateInput() {
}
}
if (updateScreen)
_system->updateScreen();
screen()->updateBackendScreen(updateScreen);
}
void KyraEngine_v1::removeInputTop() {

View File

@ -35,6 +35,9 @@
#include "graphics/palette.h"
#include "graphics/sjis.h"
#define KYRA_SCREEN_IDLE_REFRESH
namespace Kyra {
Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize)
@ -81,6 +84,8 @@ Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, co
_lineBreakChar = (_vm->gameFlags().platform == Common::kPlatformMacintosh) ? '\n' : '\r';
_yTransOffs = 0;
_idleUpdateTimer = 0;
}
Screen::~Screen() {
@ -363,9 +368,22 @@ void Screen::updateScreen() {
}
if (needRealUpdate)
_system->updateScreen();
updateBackendScreen(true);
}
#ifdef KYRA_SCREEN_IDLE_REFRESH
void Screen::updateBackendScreen(bool force) {
if (force || _system->getMillis() >= _idleUpdateTimer) {
_system->updateScreen();
_idleUpdateTimer = _system->getMillis() + (force ? SCREEN_IDLEREFRESH_RESTART_MSEC : SCREEN_IDLEREFRESH_RATE_MSEC);
}
}
#else
void Screen::updateBackendScreen(bool) {
_system->updateScreen();
}
#endif
void Screen::updateDirtyRects() {
if (_forceFullUpdate) {
_system->copyRectToScreen(getCPagePtr(0), SCREEN_W, 0, _yTransOffs, SCREEN_W, _screenHeight - _yTransOffs);
@ -789,7 +807,7 @@ void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upF
else if (_useHiColorScreen)
updateScreen();
else
_system->updateScreen();
updateBackendScreen(true);
if (!refreshed)
break;
@ -1151,7 +1169,7 @@ void Screen::shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPag
if (_vm->shouldQuit()) {
copyRegion(sx, sy, sx, sy, w, h, srcPage, dstPage);
_system->updateScreen();
updateBackendScreen(true);
}
}
@ -3051,7 +3069,7 @@ void Screen::showMouse() {
// We need to call OSystem::updateScreen here, else the mouse cursor
// will only be visible on mouse movment.
_system->updateScreen();
updateBackendScreen(true);
}
if (_mouseLockCount > 0)
@ -3115,7 +3133,7 @@ void Screen::setMouseCursor(int x, int y, const byte *shape) {
// we do not use Screen::updateScreen here
// so we can be sure that changes to page 0
// are NOT updated on the real screen here
_system->updateScreen();
updateBackendScreen(true);
}
Palette &Screen::getPalette(int num) {
@ -3266,7 +3284,7 @@ void Screen::shakeScreen(int times) {
_vm->quitGame();
}
}
_system->updateScreen();
updateBackendScreen(true);
now = _system->getMillis();
_system->delayMillis(MIN<uint>(end - now, 10));
}

View File

@ -508,7 +508,10 @@ public:
SCREEN_PAGE_SIZE = 320 * 200 + 1024,
SCREEN_OVL_SJIS_SIZE = 640 * 400,
SCREEN_PAGE_NUM = 16,
SCREEN_OVLS_NUM = 6
SCREEN_OVLS_NUM = 6,
SCREEN_IDLEREFRESH_RESTART_MSEC = 250,
SCREEN_IDLEREFRESH_RATE_MSEC = 16
};
enum CopyRegionFlags {
@ -553,7 +556,11 @@ public:
virtual void setResolution();
virtual void enableHiColorMode(bool enabled);
// refresh
void updateScreen();
void updateBackendScreen(bool force);
uint32 _idleUpdateTimer;
// debug functions
bool queryScreenDebug() const { return _debugEnabled; }

View File

@ -252,7 +252,7 @@ void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ov
// we do not use Screen::updateScreen here
// so we can be sure that changes to page 0
// are NOT updated on the real screen here
_system->updateScreen();
updateBackendScreen(true);
}
void Screen_EoB::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size) {

View File

@ -100,7 +100,7 @@ void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int
getPalette(0).copy(tempPal, startIndex, size);
setScreenPalette(getPalette(0));
_system->updateScreen();
updateBackendScreen(true);
}
void Screen_LoK::addBitBlitRect(int x, int y, int w, int h) {
@ -355,7 +355,7 @@ void Screen_LoK_16::fadePalette(const Palette &pal, int delay, const UpdateFunct
if (upFunc && upFunc->isValid())
(*upFunc)();
else
_system->updateScreen();
updateBackendScreen(true);
_vm->delay((delay >> 5) * _vm->tickLength());
}

View File

@ -654,7 +654,7 @@ void VQAMovie::play() {
_system->copyRectToScreen((const byte *)surface->getBasePtr(0, 0), surface->pitch, x, y, width, height);
}
_system->updateScreen();
_screen->updateBackendScreen(true);
_system->delayMillis(10);
}
}

View File

@ -535,7 +535,7 @@ void GUI_LoK::getInput() {
_vm->removeInputTop();
if (now - _lastScreenUpdate > 50) {
_vm->_system->updateScreen();
_screen->updateBackendScreen(true);
_lastScreenUpdate = now;
}

View File

@ -386,7 +386,7 @@ void GUI_v1::checkTextfieldInput() {
_vm->_mouseX = pos.x;
_vm->_mouseY = pos.y;
_vm->_system->updateScreen();
_screen->updateBackendScreen(true);
_lastScreenUpdate = now;
} break;
@ -396,7 +396,7 @@ void GUI_v1::checkTextfieldInput() {
}
if (now - _lastScreenUpdate > 50) {
_vm->_system->updateScreen();
_screen->updateBackendScreen(true);
_lastScreenUpdate = now;
}
@ -469,7 +469,7 @@ bool MainMenu::getInput() {
}
if (updateScreen)
_system->updateScreen();
_screen->updateBackendScreen(true);
return false;
}

View File

@ -1811,7 +1811,7 @@ int SeqPlayer_HOF::cbHOF_title(WSAMovie_v2 *wsaObj, int x, int y, int frm) {
} else if (frm == 25 && _startupSaveLoadable) {
int cp = _screen->setCurPage(0);
_screen->showMouse();
_system->updateScreen();
_screen->updateBackendScreen(true);
_result = _menu->handle(_vm->gameFlags().lang == Common::ZH_TWN ? 12 : 11) + 1;
_updateAnimations = false;

View File

@ -176,7 +176,7 @@ bool SoundMidiPC::init() {
Common::Event event;
while (isPlaying() && !_vm->shouldQuit()) {
_vm->_system->updateScreen();
_vm->screen()->updateBackendScreen(true);
_vm->_eventMan->pollEvent(event);
_vm->_system->delayMillis(10);
}

View File

@ -116,7 +116,7 @@ void KyraEngine_LoK::waitForChatToFinish(int vocFile, int16 chatDuration, const
if (nextTime - _system->getMillis() >= 10) {
_system->delayMillis(10);
_system->updateScreen();
_screen->updateBackendScreen(true);
}
}
}