[Scummvm-tracker] [ScummVM :: Bugs] #15978: ASYLUM: Sanitarium always blits fullscreen rectangles
ScummVM :: Bugs
trac at scummvm.org
Fri Aug 21 09:52:48 UTC 2026
#15978: ASYLUM: Sanitarium always blits fullscreen rectangles
------------------------+-----------------------------
Reporter: mikrosk | Owner: (none)
Type: defect | Status: new
Priority: normal | Component: Engine: Asylum
Version: | Resolution:
Keywords: performance | Game: Sanitarium
------------------------+-----------------------------
Comment (by alexbevi):
The original game rebuilds the complete scene back buffer on every render
tick. Something like the following could be used to preserve that
composition and priority behavior while comparing it with the previously
presented frame and copying only the bounding rectangle of changed pixels.
{{{#!diff
diff --git a/engines/asylum/system/screen.cpp
b/engines/asylum/system/screen.cpp
index 8a943e2ef842..61fbdb9dae01 100644
--- a/engines/asylum/system/screen.cpp
+++ b/engines/asylum/system/screen.cpp
@@ -41,9 +41,11 @@ int g_debugDrawRects;
#define TRANSPARENCY_TABLE_SIZE (256 * 256)
-Screen::Screen(AsylumEngine *vm) : _vm(vm) ,
- _useColorKey(false), _transTableCount(0), _transTable(nullptr),
_transTableBuffer(nullptr) {
+Screen::Screen(AsylumEngine *vm) : _vm(vm),
+ _presentedBufferValid(false), _useColorKey(false),
_transTableCount(0),
+ _transTable(nullptr), _transTableBuffer(nullptr) {
_backBuffer.create(640, 480,
Graphics::PixelFormat::createFormatCLUT8());
+ _presentedBuffer.create(640, 480,
Graphics::PixelFormat::createFormatCLUT8());
_flag = -1;
_clipRect = Common::Rect(0, 0, 640, 480);
@@ -61,6 +63,7 @@ Screen::Screen(AsylumEngine *vm) : _vm(vm) ,
Screen::~Screen() {
_backBuffer.free();
+ _presentedBuffer.free();
clearTransTables();
}
@@ -196,8 +199,9 @@ void Screen::clear() {
copyBackBufferToScreen();
}
-void Screen::drawWideScreenBars(int16 barSize) const {
+void Screen::drawWideScreenBars(int16 barSize) {
if (barSize > 0) {
+ invalidateScreen();
_vm->_system->fillScreen(Common::Rect(0, 0, 640, barSize),
0);
_vm->_system->fillScreen(Common::Rect(0, 480 - barSize,
640, 480), 0);
}
@@ -208,7 +212,55 @@ void Screen::fillRect(int16 x, int16 y, int16 width,
int16 height, uint32 color)
}
void Screen::copyBackBufferToScreen() {
- _vm->_system->copyRectToScreen((byte *)_backBuffer.getPixels(),
_backBuffer.w, 0, 0, _backBuffer.w, _backBuffer.h);
+ // The original RenderScene (0x40DD30) rebuilds the complete back
buffer before
+ // PresentBackBuffer (0x436120). Preserve that ordering, but avoid
uploading pixels
+ // which have not changed since the previous presentation.
+ Common::Rect dirtyRect;
+
+ if (!_presentedBufferValid) {
+ dirtyRect = Common::Rect(_backBuffer.w, _backBuffer.h);
+ } else {
+ for (int16 y = 0; y < _backBuffer.h; ++y) {
+ const byte *current = (const byte
*)_backBuffer.getBasePtr(0, y);
+ const byte *presented = (const byte
*)_presentedBuffer.getBasePtr(0, y);
+
+ if (!memcmp(current, presented, _backBuffer.w))
+ continue;
+
+ int16 left = 0;
+ while (current[left] == presented[left])
+ ++left;
+
+ int16 right = _backBuffer.w;
+ while (right > left && current[right - 1] ==
presented[right - 1])
+ --right;
+
+ Common::Rect rowRect(left, y, right, y + 1);
+ if (dirtyRect.isEmpty())
+ dirtyRect = rowRect;
+ else
+ dirtyRect.extend(rowRect);
+ }
+ }
+
+ if (dirtyRect.isEmpty()) {
+ debugC(3, kDebugLevelScene,
"[Screen::copyBackBufferToScreen] Skipping unchanged frame");
+ return;
+ }
+
+ debugC(3, kDebugLevelScene,
+ "[Screen::copyBackBufferToScreen] Presenting changed
rectangle (%d, %d)-(%d, %d)",
+ dirtyRect.left, dirtyRect.top, dirtyRect.right,
dirtyRect.bottom);
+
+ _vm->_system->copyRectToScreen((const byte
*)_backBuffer.getBasePtr(dirtyRect.left, dirtyRect.top),
+ _backBuffer.pitch, dirtyRect.left,
dirtyRect.top,
+ dirtyRect.width(),
dirtyRect.height());
+ _presentedBuffer.copyRectToSurface(_backBuffer, dirtyRect.left,
dirtyRect.top, dirtyRect);
+ _presentedBufferValid = true;
+}
+
+void Screen::invalidateScreen() {
+ _presentedBufferValid = false;
}
void Screen::clip(Common::Rect *source, Common::Rect *destination, int32
flags) const {
diff --git a/engines/asylum/system/screen.h
b/engines/asylum/system/screen.h
index 0165cd313a56..651c753e22b7 100644
--- a/engines/asylum/system/screen.h
+++ b/engines/asylum/system/screen.h
@@ -95,9 +95,11 @@ class Screen {
// Misc
void clear();
void clearDefaultColor() { memset(_mainPalette, 0, 3);
setupPalette(NULL, 0, 0); }
- void drawWideScreenBars(int16 barSize) const;
+ void drawWideScreenBars(int16 barSize);
void fillRect(int16 x, int16 y, int16 x2, int16 y2, uint32 color);
void copyBackBufferToScreen();
+ // Force the next back buffer presentation to refresh the complete
game surface.
+ void invalidateScreen();
void setFlag(int16 val) { _flag = (val < -1) ? -1 : val; }
int16 getFlag() { return _flag; }
@@ -153,6 +155,8 @@ class Screen {
AsylumEngine *_vm;
Graphics::Surface _backBuffer;
+ Graphics::Surface _presentedBuffer;
+ bool _presentedBufferValid;
Common::Rect _clipRect;
Common::Array<GraphicQueueItem> _queueItems;
diff --git a/engines/asylum/views/video.cpp
b/engines/asylum/views/video.cpp
index 0d206b2edaa9..2c3b747d7247 100644
--- a/engines/asylum/views/video.cpp
+++ b/engines/asylum/views/video.cpp
@@ -110,6 +110,7 @@ bool VideoPlayer::handleEvent(const AsylumEvent &evt)
{
if (_vm->checkGameVersion("Steam")) {
Graphics::Surface *st =
getScreen()->getSurface()->convertTo(g_system->getScreenFormat(),
_subtitlePalette);
+ getScreen()->invalidateScreen();
g_system->copyRectToScreen((const
byte *)st->getBasePtr(0, 400), st->pitch, 0, 400, 640, 80);
st->free();
delete st;
@@ -209,6 +210,7 @@ void VideoPlayer::play(const Common::Path &filename,
bool showSubtitles) {
continue;
if (_vm->checkGameVersion("Steam") ||
_vm->isAltDemo()) {
+ getScreen()->invalidateScreen();
g_system->copyRectToScreen((const byte
*)frame->getPixels(), frame->pitch, x, y, frame->w, frame->h);
} else {
if (_decoder->hasDirtyPalette())
}}}
--
Ticket URL: <https://bugs.scummvm.org/ticket/15978#comment:3>
ScummVM :: Bugs <https://bugs.scummvm.org>
ScummVM
More information about the Scummvm-tracker
mailing list