[Scummvm-git-logs] scummvm branch-2-9 -> 583660fb4cb4561f8980448a89763775359be416
mikrosk
noreply at scummvm.org
Sun Apr 20 19:41:06 UTC 2025
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
f735ad6598 BACKENDS: ATARI: graphics backend fixes from master
583660fb4c BACKENDS: ATARI: Fix crash with certain audio settings
Commit: f735ad6598f1ff751de9d672fe05eda12f4e24b9
https://github.com/scummvm/scummvm/commit/f735ad6598f1ff751de9d672fe05eda12f4e24b9
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-04-20T21:40:32+02:00
Commit Message:
BACKENDS: ATARI: graphics backend fixes from master
Changed paths:
backends/graphics/atari/atari-cursor.cpp
backends/graphics/atari/atari-cursor.h
backends/graphics/atari/atari-graphics-supervidel.h
backends/graphics/atari/atari-graphics-videl.h
backends/graphics/atari/atari-graphics.cpp
backends/graphics/atari/atari-graphics.h
backends/graphics/atari/atari-screen.cpp
backends/graphics/atari/atari-screen.h
backends/platform/atari/osystem_atari.cpp
backends/platform/atari/osystem_atari.h
backends/platform/atari/readme.txt
backends/platform/atari/readme.txt.in
graphics/blit/blit-atari.cpp
diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index b109a45fc75..f621a50c106 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -23,18 +23,24 @@
#include <cassert>
-#include "graphics/blit.h"
-
#include "atari-graphics.h"
#include "atari-screen.h"
-
-extern bool g_unalignedPitch;
+//#include "backends/platform/atari/atari-debug.h"
byte Cursor::_palette[256*3] = {};
+Cursor::Cursor(const AtariGraphicsManager *manager, const Screen *screen, int x, int y)
+ : _manager(manager)
+ , _parentScreen(screen)
+ , _boundingSurf(screen->offsettedSurf)
+ , _x(x)
+ , _y(y) {
+}
+
void Cursor::update() {
if (!_buf) {
_outOfScreen = true;
+ _savedRect = _alignedDstRect = Common::Rect();
return;
}
@@ -49,13 +55,33 @@ void Cursor::update() {
_x - _hotspotX + _width, // right
_y - _hotspotY + _height); // bottom
- _outOfScreen = !_parentScreen->offsettedSurf->clip(_srcRect, _dstRect);
+ _outOfScreen = !_boundingSurf->clip(_srcRect, _dstRect);
+
+ if (!_outOfScreen) {
+ assert(_srcRect.width() == _dstRect.width());
+ assert(_srcRect.height() == _dstRect.height());
- assert(_srcRect.width() == _dstRect.width());
- assert(_srcRect.height() == _dstRect.height());
+ const int dstBitsPerPixel = _manager->getBitsPerPixel(_parentScreen->offsettedSurf->format);
+
+ // non-direct rendering never uses 4bpp but maybe in the future ...
+ _savedRect = _manager->alignRect(
+ _dstRect.left * dstBitsPerPixel / 8, // fake 4bpp by 8bpp's x/2
+ _dstRect.top,
+ _dstRect.right * dstBitsPerPixel / 8, // fake 4bpp by 8bpp's width/2
+ _dstRect.bottom);
+
+ // this is used only in flushBackground()
+ _alignedDstRect = _manager->alignRect(
+ _dstRect.left + _xOffset,
+ _dstRect.top,
+ _dstRect.right + _xOffset,
+ _dstRect.bottom);
+ }
}
void Cursor::updatePosition(int deltaX, int deltaY) {
+ //atari_debug("Cursor::updatePosition: %d, %d", deltaX, deltaX);
+
if (deltaX == 0 && deltaY == 0)
return;
@@ -64,13 +90,13 @@ void Cursor::updatePosition(int deltaX, int deltaY) {
if (_x < 0)
_x = 0;
- else if (_x >= _parentScreen->offsettedSurf->w)
- _x = _parentScreen->offsettedSurf->w - 1;
+ else if (_x >= _boundingSurf->w)
+ _x = _boundingSurf->w - 1;
if (_y < 0)
_y = 0;
- else if (_y >= _parentScreen->offsettedSurf->h)
- _y = _parentScreen->offsettedSurf->h - 1;
+ else if (_y >= _boundingSurf->h)
+ _y = _boundingSurf->h - 1;
_positionChanged = true;
}
@@ -97,7 +123,7 @@ void Cursor::setPalette(const byte *colors, uint start, uint num) {
_surfaceChanged = true;
}
-void Cursor::convertTo(const Graphics::PixelFormat &format) {
+void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
const int cursorWidth = (_srcRect.width() + 15) & (-16);
const int cursorHeight = _height;
const bool isCLUT8 = format.isCLUT8();
@@ -115,6 +141,7 @@ void Cursor::convertTo(const Graphics::PixelFormat &format) {
_surface.create(cursorWidth, cursorHeight, format);
+ extern bool g_unalignedPitch;
const bool old_unalignedPitch = g_unalignedPitch;
g_unalignedPitch = true;
_surfaceMask.create(_surface.w / 8, _surface.h, format); // 1 bpl
@@ -169,63 +196,59 @@ void Cursor::convertTo(const Graphics::PixelFormat &format) {
}
}
-void Cursor::flushBackground(const Graphics::Surface &srcSurface, const Common::Rect &rect) {
+Common::Rect Cursor::flushBackground(const Common::Rect &alignedRect, bool directRendering) {
if (_savedRect.isEmpty())
- return;
+ return _savedRect;
+
+ if (!alignedRect.isEmpty() && alignedRect.contains(_alignedDstRect)) {
+ // better would be _visibilityChanged but update() ignores it
+ _positionChanged = true;
- if (rect.contains(_savedRect)) {
_savedRect = Common::Rect();
- } else if (rect.intersects(_savedRect)) {
- restoreBackground(srcSurface, true);
+ } else if (alignedRect.isEmpty() || alignedRect.intersects(_alignedDstRect)) {
+ // better would be _visibilityChanged but update() ignores it
+ _positionChanged = true;
+
+ if (directRendering)
+ restoreBackground();
+ else
+ return _alignedDstRect;
}
+
+ return Common::Rect();
}
-bool Cursor::restoreBackground(const Graphics::Surface &srcSurface, bool force) {
- if (_savedRect.isEmpty() || (!force && !isChanged()))
- return false;
+void Cursor::saveBackground() {
+ if (_savedRect.isEmpty())
+ return;
+ // as this is used only for direct rendering, we don't need to worry about offsettedSurf
+ // having different dimensions than the source surface
Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
- const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
- //atari_debug("Cursor::restoreBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
+ //atari_debug("Cursor::saveBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
- if (srcSurface.getPixels()) {
- _manager->copyRectToSurface(
- dstSurface, dstBitsPerPixel, srcSurface,
- _savedRect.left, _savedRect.top,
- _savedRect);
- } else {
- const int bytesPerPixel = dstSurface.format.bytesPerPixel;
-
- // restore native pixels (i.e. bitplanes)
- Graphics::copyBlit(
- (byte *)dstSurface.getPixels() + _savedRect.top * dstSurface.pitch + _savedRect.left * dstBitsPerPixel / 8,
- (const byte *)_savedBackground.getPixels(),
- dstSurface.pitch, _savedBackground.pitch,
- _savedRect.width() * dstBitsPerPixel / 8, _savedRect.height(), // fake 4bpp by 8bpp's width/2
- bytesPerPixel);
+ // save native pixels (i.e. bitplanes)
+ if (_savedBackground.w != _savedRect.width()
+ || _savedBackground.h != _savedRect.height()
+ || _savedBackground.format != dstSurface.format) {
+ _savedBackground.create(_savedRect.width(), _savedRect.height(), dstSurface.format);
}
- _savedRect = Common::Rect();
- return true;
+ _savedBackground.copyRectToSurface(dstSurface, 0, 0, _savedRect);
}
-bool Cursor::draw(bool directRendering, bool force) {
- if (!isVisible() || (!force && !isChanged()))
- return false;
-
+void Cursor::draw() {
Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
- // always work with aligned rect
- _savedRect = _manager->alignRect(_dstRect);
+ if (_surfaceChanged || _srcRect != _previousSrcRect) {
+ _previousSrcRect = _srcRect;
- if (_surfaceChanged || _width != _srcRect.width()) {
- // TODO: check for change, not just different width so it's not called over and over again ...
- // TODO: some sort of in-place C2P directly into convertTo() ...
- convertTo(dstSurface.format);
+ // TODO: some sort of in-place C2P directly into convertSurfaceTo() ...
+ convertSurfaceTo(dstSurface.format);
{
// c2p in-place (will do nothing on regular Surface::copyRectToSurface)
Graphics::Surface surf;
@@ -236,36 +259,40 @@ bool Cursor::draw(bool directRendering, bool force) {
_surface.getPixels(),
_surface.format);
_manager->copyRectToSurface(
- surf, dstBitsPerPixel, _surface,
+ surf, _surface,
0, 0,
Common::Rect(_surface.w, _surface.h));
}
}
- if (directRendering) {
- // store native pixels (i.e. bitplanes)
- if (_savedBackground.w != _savedRect.width()
- || _savedBackground.h != _savedRect.height()
- || _savedBackground.format != dstSurface.format) {
- _savedBackground.create(_savedRect.width(), _savedRect.height(), dstSurface.format);
- _savedBackground.pitch = _savedBackground.pitch * dstBitsPerPixel / 8;
- }
-
- Graphics::copyBlit(
- (byte *)_savedBackground.getPixels(),
- (const byte *)dstSurface.getPixels() + _savedRect.top * dstSurface.pitch + _savedRect.left * dstBitsPerPixel / 8,
- _savedBackground.pitch, dstSurface.pitch,
- _savedRect.width() * dstBitsPerPixel / 8, _savedRect.height(), // fake 4bpp by 8bpp's width/2
- dstSurface.format.bytesPerPixel);
- }
-
// don't use _srcRect.right as 'x2' as this must be aligned first
- // (_surface.w is recalculated thanks to convertTo())
+ // (_surface.w is recalculated thanks to convertSurfaceTo())
_manager->drawMaskedSprite(
- dstSurface, dstBitsPerPixel, _surface, _surfaceMask,
- _dstRect.left, _dstRect.top,
+ dstSurface,
+ _surface, _surfaceMask,
+ _dstRect.left + _xOffset, _dstRect.top,
Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
_visibilityChanged = _positionChanged = _surfaceChanged = false;
- return true;
+}
+
+void Cursor::restoreBackground() {
+ if (_savedRect.isEmpty())
+ return;
+
+ assert(_savedBackground.getPixels());
+
+ //atari_debug("Cursor::restoreBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
+
+ // as this is used only for direct rendering, we don't need to worry about offsettedSurf
+ // having different dimensions than the source surface
+ Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
+
+ // restore native pixels (i.e. bitplanes)
+ dstSurface.copyRectToSurface(
+ _savedBackground,
+ _savedRect.left, _savedRect.top,
+ Common::Rect(_savedBackground.w, _savedBackground.h));
+
+ _savedRect = Common::Rect();
}
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 2de90f5da3a..7413182e549 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -25,6 +25,7 @@
#include "common/rect.h"
#include "common/scummsys.h"
#include "graphics/surface.h"
+//#include "backends/platform/atari/atari-debug.h"
class AtariGraphicsManager;
struct Screen;
@@ -36,17 +37,17 @@ struct Screen;
// These always get updates by ScummVM, no need to differentiate between engines and the overlay.
struct Cursor {
- Cursor(AtariGraphicsManager *manager, Screen *screen)
- : _manager(manager)
- , _parentScreen(screen) {
- }
+ Cursor(const AtariGraphicsManager *manager, const Screen *screen, int x, int y);
+
+ void reset(const Graphics::Surface *boundingSurf, int xOffset) {
+ _boundingSurf = boundingSurf;
+ _xOffset = xOffset;
- void reset() {
_positionChanged = true;
_surfaceChanged = true;
_visibilityChanged = false;
- _savedRect = Common::Rect();
+ _savedRect = _previousSrcRect = _alignedDstRect = Common::Rect();
}
// updates outOfScreen OR srcRect/dstRect (only if visible/needed)
@@ -72,6 +73,8 @@ struct Cursor {
return Common::Point(_x, _y);
}
void setPosition(int x, int y) {
+ //atari_debug("Cursor::setPosition: %d, %d", x, y);
+
if (_x == x && _y == y)
return;
@@ -85,7 +88,7 @@ struct Cursor {
// surface
void setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor);
void setPalette(const byte *colors, uint start, uint num);
- void convertTo(const Graphics::PixelFormat &format);
+ void convertSurfaceTo(const Graphics::PixelFormat &format);
bool isVisible() const {
return !_outOfScreen && _visible;
@@ -94,32 +97,35 @@ struct Cursor {
return _positionChanged || _surfaceChanged || _visibilityChanged;
}
- bool intersects(const Common::Rect &rect) const {
- return rect.intersects(_dstRect);
- }
-
- void flushBackground(const Graphics::Surface &srcSurface, const Common::Rect &rect);
- bool restoreBackground(const Graphics::Surface &srcSurface, bool force);
- bool draw(bool directRendering, bool force);
+ Common::Rect flushBackground(const Common::Rect &alignedRect, bool directRendering);
+ void saveBackground();
+ void draw();
private:
+ void restoreBackground();
+
static byte _palette[256*3];
- AtariGraphicsManager *_manager;
- Screen *_parentScreen;
+ const AtariGraphicsManager *_manager;
+ const Screen *_parentScreen;
+ const Graphics::Surface *_boundingSurf;
+ int _xOffset = 0;
bool _positionChanged = true;
bool _surfaceChanged = true;
bool _visibilityChanged = false;
bool _visible = false;
- int _x = -1, _y = -1;
+ int _x;
+ int _y;
bool _outOfScreen = true;
Common::Rect _srcRect;
Common::Rect _dstRect;
- Graphics::Surface _savedBackground; // used by direct rendering
+ Graphics::Surface _savedBackground;
Common::Rect _savedRect;
+ Common::Rect _previousSrcRect;
+ Common::Rect _alignedDstRect;
// related to 'surface'
const byte *_buf = nullptr;
@@ -129,6 +135,10 @@ private:
int _hotspotY;
uint32 _keycolor;
+ // TODO: make all surface-related variables and functions static, similar to _palette/
+ // but there's a catch: we still need _surfaceChanged instantiated and convertTo may
+ // be called when clipping changes. Perhaps Cursor should be a singleton and those
+ // flags moved to Screen...
Graphics::Surface _surface;
Graphics::Surface _surfaceMask;
int _rShift, _gShift, _bShift;
diff --git a/backends/graphics/atari/atari-graphics-supervidel.h b/backends/graphics/atari/atari-graphics-supervidel.h
index 8dc7affe37f..28e34303331 100644
--- a/backends/graphics/atari/atari-graphics-supervidel.h
+++ b/backends/graphics/atari/atari-graphics-supervidel.h
@@ -101,11 +101,11 @@ private:
return [](void *ptr) { Mfree((uintptr)ptr & 0x00FFFFFF); };
}
- void drawMaskedSprite(Graphics::Surface &dstSurface, int dstBitsPerPixel,
+ void drawMaskedSprite(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
int destX, int destY,
- const Common::Rect &subRect) override {
- assert(dstBitsPerPixel == 8);
+ const Common::Rect &subRect) const override {
+ assert(dstSurface.format == Graphics::PixelFormat::createFormatCLUT8());
assert(subRect.width() % 16 == 0);
assert(subRect.width() == srcSurface.w);
@@ -122,7 +122,7 @@ private:
const uint16 m = *mask;
if (m == 0xFFFF) {
- // all 16 pixels transparentm6
+ // all 16 pixels transparent
src += 16;
dst += 16;
continue;
@@ -145,10 +145,6 @@ private:
}
}
- Common::Rect alignRect(int x, int y, int w, int h) const override {
- return Common::Rect(x, y, x + w, y + h);
- }
-
static long hasSvRamBoosted() {
register long ret __asm__ ("d0") = 0;
diff --git a/backends/graphics/atari/atari-graphics-videl.h b/backends/graphics/atari/atari-graphics-videl.h
index 862409b91f1..15126436e67 100644
--- a/backends/graphics/atari/atari-graphics-videl.h
+++ b/backends/graphics/atari/atari-graphics-videl.h
@@ -41,9 +41,16 @@ public:
}
private:
- void copyRectToSurface(Graphics::Surface &dstSurface, int dstBitsPerPixel, const Graphics::Surface &srcSurface,
+ void copyRectToSurface(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
int destX, int destY,
const Common::Rect &subRect) const override {
+ assert(subRect.left % 16 == 0);
+ assert(subRect.width() % 16 == 0);
+ assert(destX % 16 == 0);
+ assert(srcSurface.format == dstSurface.format);
+
+ const int bitsPerPixel = getBitsPerPixel(dstSurface.format);
+
// 'pChunkyEnd' is a delicate parameter: the c2p routine compares it to the address register
// used for pixel reading; two common mistakes:
// 1. (subRect.left, subRect.bottom) = beginning of the next line *including the offset*
@@ -51,9 +58,9 @@ private:
const byte *pChunky = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
const byte *pChunkyEnd = (const byte *)srcSurface.getBasePtr(subRect.right, subRect.bottom-1);
- byte *pScreen = (byte *)dstSurface.getPixels() + destY * dstSurface.pitch + destX * dstBitsPerPixel/8;
+ byte *pScreen = (byte *)dstSurface.getPixels() + destY * dstSurface.pitch + destX * bitsPerPixel/8;
- if (dstBitsPerPixel == 8) {
+ if (bitsPerPixel == 8) {
if (srcSurface.pitch == subRect.width()) {
if (srcSurface.pitch == dstSurface.pitch) {
asm_c2p1x1_8(pChunky, pChunkyEnd, pScreen);
@@ -85,17 +92,23 @@ private:
}
}
- void drawMaskedSprite(Graphics::Surface &dstSurface, int dstBitsPerPixel,
+ void drawMaskedSprite(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
int destX, int destY,
- const Common::Rect &subRect) override {
- if (dstBitsPerPixel == 4) {
+ const Common::Rect &subRect) const override {
+ assert(subRect.width() % 16 == 0);
+ assert(subRect.width() == srcSurface.w);
+ assert(srcSurface.format == dstSurface.format);
+
+ const int bitsPerPixel = getBitsPerPixel(dstSurface.format);
+
+ if (bitsPerPixel == 4) {
asm_draw_4bpl_sprite(
(uint16 *)dstSurface.getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
destX, destY,
dstSurface.pitch, subRect.width(), subRect.height());
- } else if (dstBitsPerPixel == 8) {
+ } else if (bitsPerPixel == 8) {
asm_draw_8bpl_sprite(
(uint16 *)dstSurface.getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
@@ -103,10 +116,6 @@ private:
dstSurface.pitch, subRect.width(), subRect.height());
}
}
-
- Common::Rect alignRect(int x, int y, int w, int h) const override {
- return Common::Rect(x & (-16), y, (x + w + 15) & (-16), y + h);
- }
};
#endif
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 84c8c1c59ea..097fb6a35d3 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -43,7 +43,6 @@
#define SCREEN_ACTIVE
-bool g_unalignedPitch = false;
mspace g_mspace = nullptr;
static const Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::createFormatCLUT8();
@@ -408,6 +407,7 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
atari_debug("endGFXTransaction");
_pendingState.inTransaction = false;
+ _ignoreCursorChanges = false;
int error = OSystem::TransactionError::kTransactionSuccess;
bool hasPendingGraphicsMode = false;
@@ -422,10 +422,17 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
}
if (_pendingState.width > 0 && _pendingState.height > 0) {
+ extern bool g_unalignedPitch;
+
if (_pendingState.width > getMaximumScreenWidth() || _pendingState.height > getMaximumScreenHeight()) {
error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
- } else if (_pendingState.width % 16 != 0 && !hasSuperVidel()) {
- atari_warning("Requested width not divisible by 16, please report");
+ } else if (((hasPendingGraphicsMode && _pendingState.mode == kDirectRendering)
+ || (!hasPendingGraphicsMode && _currentState.mode == kDirectRendering))
+ && (_pendingState.width % 16 != 0 || g_unalignedPitch)
+ && !hasSuperVidel()) {
+ atari_warning("Engine surfaces not divisible by 16, aborting");
+ // engineDone is not called
+ g_unalignedPitch = false;
error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
} else if (_overlayState == kOverlayIgnoredHide || _currentState.width != _pendingState.width || _currentState.height != _pendingState.height) {
// if kOverlayIgnoredHide and with valid w/h, force a video mode reset
@@ -453,13 +460,25 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
}
if ((hasPendingGraphicsMode || hasPendingSize) && _currentState.isValid()) {
- _chunkySurface.init(_currentState.width, _currentState.height, _currentState.width,
+ int c2pWidth = _currentState.width;
+
+ if (!hasSuperVidel()) {
+ // make sure that c2p width is always divisible by 16
+ c2pWidth = (c2pWidth + 15) & -16;
+ }
+
+ _chunkySurface.init(c2pWidth, _currentState.height, c2pWidth,
_chunkySurface.getPixels(), _currentState.format);
- _screen[kFrontBuffer]->reset(_currentState.width, _currentState.height, 8, true);
+ const int xOffset = (c2pWidth - _currentState.width) / 2;
+
+ _chunkySurfaceOffsetted.init(_currentState.width, _currentState.height, c2pWidth,
+ _chunkySurface.getBasePtr(xOffset, 0), _currentState.format);
+
+ _screen[kFrontBuffer]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
if (_currentState.mode > kSingleBuffering) {
- _screen[kBackBuffer1]->reset(_currentState.width, _currentState.height, 8, true);
- _screen[kBackBuffer2]->reset(_currentState.width, _currentState.height, 8, true);
+ _screen[kBackBuffer1]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
+ _screen[kBackBuffer2]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
}
if (hasPendingSize)
@@ -473,7 +492,6 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
_pendingScreenChanges.queuePalette();
if (_overlayState == kOverlayIgnoredHide) {
- _checkUnalignedPitch = true;
_overlayState = kOverlayHidden;
_ignoreHideOverlay = false;
_pendingScreenChanges.queueAll();
@@ -542,14 +560,18 @@ void AtariGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, i
Graphics::Surface &dstSurface = *lockScreen();
- copyRectToScreenInternal(
+ const bool directRendering = _currentState.mode == kDirectRendering;
+
+ addDirtyRectToScreens(
dstSurface,
- buf, pitch, x, y, w, h,
- _currentState.format, _currentState.mode == kDirectRendering);
+ x, y, w, h,
+ directRendering);
- unlockScreenInternal(
+ copyRectToScreenInternal(
dstSurface,
- x, y, w, h);
+ buf, pitch, x, y, w, h,
+ _currentState.format,
+ directRendering);
}
Graphics::Surface *AtariGraphicsManager::lockScreen() {
@@ -557,7 +579,7 @@ Graphics::Surface *AtariGraphicsManager::lockScreen() {
return _currentState.mode == kDirectRendering
? _screen[kFrontBuffer]->offsettedSurf
- : &_chunkySurface;
+ : &_chunkySurfaceOffsetted;
}
void AtariGraphicsManager::unlockScreen() {
@@ -565,9 +587,10 @@ void AtariGraphicsManager::unlockScreen() {
//atari_debug("unlockScreen: %d x %d", dstSurface.w, dstSurface.h);
- unlockScreenInternal(
+ addDirtyRectToScreens(
dstSurface,
- 0, 0, dstSurface.w, dstSurface.h);
+ 0, 0, dstSurface.w, dstSurface.h,
+ _currentState.mode == kDirectRendering);
}
void AtariGraphicsManager::fillScreen(uint32 col) {
@@ -602,36 +625,6 @@ void AtariGraphicsManager::updateScreen() {
// avoid falling into the atari_debugger (screen may not not initialized yet)
Common::setErrorHandler(nullptr);
- if (_checkUnalignedPitch) {
- const Common::ConfigManager::Domain *activeDomain = ConfMan.getActiveDomain();
- if (activeDomain) {
- // FIXME: Some engines are too bound to linear surfaces that it is very
- // hard to repair them. So instead of polluting the engine with
- // Surface::init() & delete[] Surface::getPixels() just use this hack.
- const Common::String engineId = activeDomain->getValOrDefault("engineid");
- const Common::String gameId = activeDomain->getValOrDefault("gameid");
-
- atari_debug("checking %s/%s", engineId.c_str(), gameId.c_str());
-
- if (engineId == "composer"
- || engineId == "hypno"
- || engineId == "mohawk"
- || engineId == "parallaction"
- || engineId == "private"
- || (engineId == "sci"
- && (gameId == "phantasmagoria" || gameId == "shivers"))
- || engineId == "sherlock"
- || engineId == "teenagent"
- || engineId == "tsage") {
- g_unalignedPitch = true;
- } else {
- g_unalignedPitch = false;
- }
- }
-
- _checkUnalignedPitch = false;
- }
-
Screen *workScreen = nullptr;
Graphics::Surface *srcSurface = nullptr;
if (_overlayState == kOverlayVisible || _overlayState == kOverlayIgnoredHide) {
@@ -657,12 +650,9 @@ void AtariGraphicsManager::updateScreen() {
}
assert(workScreen);
- workScreen->cursor.update();
bool screenUpdated = updateScreenInternal(workScreen, srcSurface ? *srcSurface : Graphics::Surface());
- workScreen->clearDirtyRects();
-
#ifdef SCREEN_ACTIVE
// this assume that the screen surface is not going to be used yet
_pendingScreenChanges.applyBeforeVblLock(*workScreen);
@@ -743,13 +733,17 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
}
if (_currentState.mode == kDirectRendering) {
- _screen[kFrontBuffer]->cursor.restoreBackground(Graphics::Surface(), true);
+ _screen[kFrontBuffer]->cursor.flushBackground(Common::Rect(), true);
}
_pendingScreenChanges.setScreenSurface(&_screen[kOverlayBuffer]->surf);
- // do not cache dirtyRects and oldCursorRect
- _screen[kOverlayBuffer]->reset(getOverlayWidth(), getOverlayHeight(), getBitsPerPixel(getOverlayFormat()), false);
+ // do not cache dirtyRects and saved cursor rect
+ _screen[kOverlayBuffer]->reset(
+ getOverlayWidth(), getOverlayHeight(),
+ getBitsPerPixel(getOverlayFormat()),
+ *lockOverlay(), 0,
+ false);
_overlayState = kOverlayVisible;
@@ -805,7 +799,7 @@ void AtariGraphicsManager::clearOverlay() {
return;
const Graphics::Surface &sourceSurface =
- _currentState.mode == kDirectRendering ? *_screen[kFrontBuffer]->offsettedSurf : _chunkySurface;
+ _currentState.mode == kDirectRendering ? *_screen[kFrontBuffer]->offsettedSurf : _chunkySurfaceOffsetted;
const bool upscale = _overlaySurface.w / sourceSurface.w >= 2 && _overlaySurface.h / sourceSurface.h >= 2;
@@ -873,7 +867,7 @@ void AtariGraphicsManager::clearOverlay() {
// right rect
_overlaySurface.fillRect(Common::Rect(_overlaySurface.w - hzOffset, vOffset, _overlaySurface.w, _overlaySurface.h - vOffset), 0);
- _screen[kOverlayBuffer]->addDirtyRect(_overlaySurface, Common::Rect(_overlaySurface.w, _overlaySurface.h), false);
+ _screen[kOverlayBuffer]->addDirtyRect(_overlaySurface, 0, 0, _overlaySurface.w, _overlaySurface.h, false);
}
void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
@@ -896,41 +890,53 @@ void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
//atari_debug("copyRectToOverlay: %d, %d, %d(%d), %d", x, y, w, pitch, h);
+ Graphics::Surface &dstSurface = *lockOverlay();
+
const bool directRendering = isOverlayDirectRendering();
- Graphics::Surface &dstSurface = directRendering
- ? *_screen[kOverlayBuffer]->offsettedSurf
- : _overlaySurface;
+ _screen[kOverlayBuffer]->addDirtyRect(
+ dstSurface,
+ x, y, w, h,
+ directRendering);
copyRectToScreenInternal(
dstSurface,
buf, pitch, x, y, w, h,
getOverlayFormat(),
directRendering);
+}
- const Common::Rect rect = alignRect(x, y, w, h);
- _screen[kOverlayBuffer]->addDirtyRect(dstSurface, rect, directRendering);
+Graphics::Surface *AtariGraphicsManager::lockOverlay() {
+ //atari_debug("lockOverlay");
+
+ return isOverlayDirectRendering()
+ ? _screen[kOverlayBuffer]->offsettedSurf
+ : &_overlaySurface;
}
bool AtariGraphicsManager::showMouse(bool visible) {
- //atari_debug("showMouse: %d", visible);
+ //atari_debug("showMouse: %d; ignored: %d", visible, _ignoreCursorChanges);
- bool last;
+ if (_ignoreCursorChanges)
+ return visible;
- if (isOverlayVisible()) {
- last = _screen[kOverlayBuffer]->cursor.setVisible(visible);
- } else if (_currentState.mode <= kSingleBuffering) {
- last = _screen[kFrontBuffer]->cursor.setVisible(visible);
- } else {
- last = _screen[kBackBuffer1]->cursor.setVisible(visible);
+ bool lastOverlay, lastFront, lastBack1 = false;
+
+ // TODO: cursor.flushBackground() if !visible
+ lastOverlay = _screen[kOverlayBuffer]->cursor.setVisible(visible);
+ lastFront = _screen[kFrontBuffer]->cursor.setVisible(visible);
+
+ if (_currentState.mode == kTripleBuffering) {
+ lastBack1 = _screen[kBackBuffer1]->cursor.setVisible(visible);
_screen[kBackBuffer2]->cursor.setVisible(visible);
- _screen[kFrontBuffer]->cursor.setVisible(visible);
}
- // don't rely on engines to call it (if they don't it confuses the cursor restore logic)
- updateScreen();
-
- return last;
+ if (isOverlayVisible())
+ return lastOverlay;
+ else if (_currentState.mode <= kSingleBuffering)
+ return lastFront;
+ else
+ return lastBack1;
}
void AtariGraphicsManager::warpMouse(int x, int y) {
@@ -949,7 +955,11 @@ void AtariGraphicsManager::warpMouse(int x, int y) {
void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor,
bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
- //atari_debug("setMouseCursor: %d, %d, %d, %d, %d, %d", w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1);
+ //atari_debug("setMouseCursor: %d, %d, %d, %d, %d, %d; ignored: %d",
+ // w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1, _ignoreCursorChanges);
+
+ if (_ignoreCursorChanges)
+ return;
if (mask)
atari_warning("AtariGraphicsManager::setMouseCursor: Masks are not supported");
@@ -957,27 +967,25 @@ void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int h
if (format)
assert(*format == PIXELFORMAT_CLUT8);
- if (isOverlayVisible()) {
- _screen[kOverlayBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
- } else if (_currentState.mode <= kSingleBuffering) {
- _screen[kFrontBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
- } else {
+ _screen[kOverlayBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
+ _screen[kFrontBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
+
+ if (_currentState.mode == kTripleBuffering) {
_screen[kBackBuffer1]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
_screen[kBackBuffer2]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
- _screen[kFrontBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
}
}
void AtariGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
atari_debug("setCursorPalette: %d, %d", start, num);
- if (isOverlayVisible()) {
- // cursor palette is supported only in the overlay
- _screen[kOverlayBuffer]->cursor.setPalette(colors, start, num);
- }
+ // cursor palette is supported only in the overlay
+ _screen[kOverlayBuffer]->cursor.setPalette(colors, start, num);
}
void AtariGraphicsManager::updateMousePosition(int deltaX, int deltaY) {
+ //atari_debug("updateMousePosition: %d, %d", deltaX, deltaY);
+
if (isOverlayVisible()) {
_screen[kOverlayBuffer]->cursor.updatePosition(deltaX, deltaY);
} else if (_currentState.mode <= kSingleBuffering) {
@@ -997,10 +1005,12 @@ bool AtariGraphicsManager::notifyEvent(const Common::Event &event) {
// clear work screen: this is needed if *next* game shows an error upon startup
Graphics::Surface &surf = _currentState.mode == kDirectRendering
? *_screen[kFrontBuffer]->offsettedSurf
- : _chunkySurface;
+ : _chunkySurfaceOffsetted;
surf.fillRect(Common::Rect(surf.w, surf.h), 0);
_ignoreHideOverlay = true;
+ // gui manager would want to hide overlay, set game cursor etc
+ _ignoreCursorChanges = true;
return false;
}
break;
@@ -1043,6 +1053,10 @@ Common::Keymap *AtariGraphicsManager::getKeymap() const {
return keymap;
}
+int AtariGraphicsManager::getBitsPerPixel(const Graphics::PixelFormat &format) const {
+ return format == PIXELFORMAT_RGB121 ? 4 : 8;
+}
+
void AtariGraphicsManager::allocateSurfaces() {
for (int i : { kFrontBuffer, kBackBuffer1, kBackBuffer2 }) {
_screen[i] = new Screen(this, getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8, &_palette);
@@ -1050,6 +1064,7 @@ void AtariGraphicsManager::allocateSurfaces() {
_screen[kOverlayBuffer] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
_chunkySurface.create(getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8);
+ _chunkySurfaceOffsetted = _chunkySurface;
_overlaySurface.create(getOverlayWidth(), getOverlayHeight(), getOverlayFormat());
}
@@ -1060,17 +1075,16 @@ void AtariGraphicsManager::freeSurfaces() {
}
_chunkySurface.free();
+ _chunkySurfaceOffsetted = _chunkySurface;
_overlaySurface.free();
}
-void AtariGraphicsManager::unlockScreenInternal(const Graphics::Surface &dstSurface, int x, int y, int w, int h) {
- const bool directRendering = _currentState.mode == kDirectRendering;
- const Common::Rect rect = alignRect(x, y, w, h);
- _screen[kFrontBuffer]->addDirtyRect(dstSurface, rect, directRendering);
+void AtariGraphicsManager::addDirtyRectToScreens(const Graphics::Surface &dstSurface, int x, int y, int w, int h, bool directRendering) {
+ _screen[kFrontBuffer]->addDirtyRect(dstSurface, x, y, w, h, directRendering);
if (_currentState.mode > kSingleBuffering) {
- _screen[kBackBuffer1]->addDirtyRect(dstSurface, rect, directRendering);
- _screen[kBackBuffer2]->addDirtyRect(dstSurface, rect, directRendering);
+ _screen[kBackBuffer1]->addDirtyRect(dstSurface, x, y, w, h, directRendering);
+ _screen[kBackBuffer2]->addDirtyRect(dstSurface, x, y, w, h, directRendering);
}
}
@@ -1082,30 +1096,42 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
Cursor &cursor = dstScreen->cursor;
const bool directRendering = srcSurface.getPixels() == nullptr;
- const int dstBitsPerPixel = getBitsPerPixel(dstSurface->format);
bool updated = false;
- const bool cursorDrawEnabled = cursor.isVisible();
- bool forceCursorDraw = cursorDrawEnabled && (dstScreen->fullRedraw || cursor.isChanged());
-
lockSuperBlitter();
- for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
- if (cursorDrawEnabled && !forceCursorDraw)
- forceCursorDraw = cursor.intersects(*it);
-
- if (!directRendering) {
- copyRectToSurface(*dstSurface, dstBitsPerPixel, srcSurface, it->left, it->top, *it);
+ if (cursor.isChanged()) {
+ const Common::Rect cursorBackgroundRect = cursor.flushBackground(Common::Rect(), directRendering);
+ if (!cursorBackgroundRect.isEmpty()) {
+ copyRectToSurface(*dstSurface, srcSurface, cursorBackgroundRect.left, cursorBackgroundRect.top, cursorBackgroundRect);
updated |= true;
}
}
- updated |= cursor.restoreBackground(srcSurface, false);
+ // update cursor rects and visibility flag (if out of screen)
+ cursor.update();
+ const bool drawCursor = cursor.isVisible() && (dstScreen->fullRedraw || cursor.isChanged());
+
+ if (!directRendering) {
+ for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
+ copyRectToSurface(*dstSurface, srcSurface, it->left, it->top, *it);
+ }
+ updated |= !dirtyRects.empty();
+ } else if (drawCursor) {
+ cursor.saveBackground();
+ }
+
+ // unlock here because cursor.draw() is a software blit
unlockSuperBlitter();
- updated |= cursor.draw(directRendering, forceCursorDraw);
+ if (drawCursor) {
+ cursor.draw();
+ updated |= true;
+ }
+
+ dstScreen->clearDirtyRects();
return updated;
}
@@ -1113,9 +1139,9 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
void AtariGraphicsManager::copyRectToScreenInternal(Graphics::Surface &dstSurface,
const void *buf, int pitch, int x, int y, int w, int h,
const Graphics::PixelFormat &format, bool directRendering) {
- const Common::Rect rect = alignRect(x, y, w, h);
-
if (directRendering) {
+ const Common::Rect rect = alignRect(x, y, x + w, y + h);
+
// TODO: mask the unaligned parts and copy the rest
Graphics::Surface srcSurface;
byte *srcBuf = (byte *)const_cast<void *>(buf);
@@ -1123,24 +1149,10 @@ void AtariGraphicsManager::copyRectToScreenInternal(Graphics::Surface &dstSurfac
srcSurface.init(rect.width(), rect.height(), pitch, srcBuf, format);
copyRectToSurface(
- dstSurface, getBitsPerPixel(format), srcSurface,
+ dstSurface, srcSurface,
rect.left, rect.top,
Common::Rect(rect.width(), rect.height()));
} else {
dstSurface.copyRectToSurface(buf, pitch, x, y, w, h);
}
}
-
-int AtariGraphicsManager::getBitsPerPixel(const Graphics::PixelFormat &format) const {
- return format == PIXELFORMAT_RGB121 ? 4 : 8;
-}
-
-bool AtariGraphicsManager::isOverlayDirectRendering() const {
- // overlay is direct rendered if in the launcher or if game is directly rendered
- // (on SuperVidel we always want to use shading/transparency but its direct rendering is fine and supported)
- return !hasSuperVidel()
-#ifndef DISABLE_FANCY_THEMES
- && (ConfMan.getActiveDomain() == nullptr || _currentState.mode == kDirectRendering)
-#endif
- ;
-}
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index fd437228d3d..3672c5554f6 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -31,6 +31,7 @@
#include "graphics/surface.h"
#include "atari-cursor.h"
+#include "atari-graphics-superblitter.h"
#include "atari-pendingscreenchanges.h"
#include "atari-screen.h"
@@ -117,6 +118,7 @@ protected:
typedef void* (*AtariMemAlloc)(size_t bytes);
typedef void (*AtariMemFree)(void *ptr);
+ int getBitsPerPixel(const Graphics::PixelFormat &format) const;
void allocateSurfaces();
void freeSurfaces();
@@ -140,16 +142,40 @@ private:
int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 320 : 320*1.2); }
#endif
- void unlockScreenInternal(const Graphics::Surface &dstSurface,
- int x, int y, int w, int h);
+ void addDirtyRectToScreens(const Graphics::Surface &dstSurface,
+ int x, int y, int w, int h, bool directRendering);
bool updateScreenInternal(Screen *dstScreen, const Graphics::Surface &srcSurface);
void copyRectToScreenInternal(Graphics::Surface &dstSurface,
const void *buf, int pitch, int x, int y, int w, int h,
const Graphics::PixelFormat &format, bool directRendering);
- int getBitsPerPixel(const Graphics::PixelFormat &format) const;
+ bool isOverlayDirectRendering() const {
+ // see osystem_atari.cpp
+ extern bool g_gameEngineActive;
+
+ // overlay is direct rendered if in the launcher or if game is directly rendered
+ // (on SuperVidel we always want to use shading/transparency but its direct rendering is fine and supported)
+ return !hasSuperVidel()
+#ifndef DISABLE_FANCY_THEMES
+ && (!g_gameEngineActive || _currentState.mode == kDirectRendering)
+#endif
+ ;
+ }
+
+ Graphics::Surface *lockOverlay();
- bool isOverlayDirectRendering() const;
+ Common::Rect alignRect(int x1, int y1, int x2, int y2) const {
+ // make non-virtual for performance reasons
+ return hasSuperVidel()
+ ? Common::Rect(x1, y1, x2, y2)
+ : Common::Rect(x1 & (-16), y1, (x2 + 15) & (-16), y2);
+ }
+ Common::Rect alignRect(const Common::Rect &rect) const {
+ // make non-virtual for performance reasons
+ return hasSuperVidel()
+ ? rect
+ : Common::Rect(rect.left & (-16), rect.top, (rect.right + 15) & (-16), rect.bottom);
+ }
virtual AtariMemAlloc getStRamAllocFunc() const {
return [](size_t bytes) { return (void*)Mxalloc(bytes, MX_STRAM); };
@@ -158,26 +184,19 @@ private:
return [](void *ptr) { Mfree(ptr); };
}
- virtual void copyRectToSurface(Graphics::Surface &dstSurface, int dstBitsPerPixel, const Graphics::Surface &srcSurface,
+ virtual void copyRectToSurface(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
int destX, int destY,
const Common::Rect &subRect) const {
dstSurface.copyRectToSurface(srcSurface, destX, destY, subRect);
}
- virtual void drawMaskedSprite(Graphics::Surface &dstSurface, int dstBitsPerPixel,
+ virtual void drawMaskedSprite(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
int destX, int destY,
- const Common::Rect &subRect) = 0;
-
- virtual Common::Rect alignRect(int x, int y, int w, int h) const = 0;
-
- Common::Rect alignRect(const Common::Rect &rect) const {
- return alignRect(rect.left, rect.top, rect.width(), rect.height());
- }
+ const Common::Rect &subRect) const = 0;
bool _vgaMonitor = true;
bool _tt = false;
- bool _checkUnalignedPitch = false;
struct GraphicsState {
GraphicsState()
@@ -216,6 +235,7 @@ private:
Screen *_screen[kBufferCount] = {};
Graphics::Surface _chunkySurface;
+ Graphics::Surface _chunkySurfaceOffsetted;
enum {
kOverlayVisible,
@@ -225,6 +245,7 @@ private:
int _overlayState = kOverlayHidden;
bool _ignoreHideOverlay = true;
Graphics::Surface _overlaySurface;
+ bool _ignoreCursorChanges = false;
Palette _palette;
Palette _overlayPalette;
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index 6c6521cd167..dd591a2965d 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -25,10 +25,11 @@
#include "atari-graphics.h"
#include "atari-graphics-superblitter.h"
+#include "backends/platform/atari/atari-debug.h"
Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
: _manager(manager)
- , cursor(manager, this)
+ , cursor(manager, this, width / 2, height / 2)
, palette(palette_) {
const AtariGraphicsManager::AtariMemAlloc &allocFunc = _manager->getStRamAllocFunc();
@@ -44,6 +45,7 @@ Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graph
error("Failed to allocate memory in ST RAM");
}
+ // TODO: use mspace_calloc similar as what we do with SuperVidel
surf.setPixels((void *)(((uintptr)pixelsUnaligned + sizeof(uintptr) + ALIGN - 1) & (-ALIGN)));
// store the unaligned pointer for later release
@@ -63,11 +65,13 @@ Screen::~Screen() {
freeFunc((void *)*((uintptr *)surf.getPixels() - 1));
}
-void Screen::reset(int width, int height, int bitsPerPixel, bool resetCursorPosition) {
+void Screen::reset(int width, int height, int bitsPerPixel, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition) {
+ _xOffset = xOffset;
+
clearDirtyRects();
- cursor.reset();
+ cursor.reset(&boundingSurf, xOffset);
if (resetCursorPosition)
- cursor.setPosition(width / 2, height / 2);
+ cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
rez = -1;
mode = -1;
@@ -134,24 +138,34 @@ void Screen::reset(int width, int height, int bitsPerPixel, bool resetCursorPosi
surf.format);
}
-void Screen::addDirtyRect(const Graphics::Surface &srcSurface, const Common::Rect &rect, bool directRendering) {
+void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering) {
if (fullRedraw)
return;
- if ((rect.width() == srcSurface.w && rect.height() == srcSurface.h)
+ if ((w == srcSurface.w && h == srcSurface.h)
|| dirtyRects.size() == 128) { // 320x200 can hold at most 250 16x16 rectangles
//atari_debug("addDirtyRect[%d]: purge %d x %d", (int)dirtyRects.size(), srcSurface.w, srcSurface.h);
dirtyRects.clear();
- dirtyRects.emplace(srcSurface.w, srcSurface.h);
+ // don't use x/y/w/h, the 2nd expression may be true
+ // also, it's ok if e.g. w = 630 gets aligned to w = 640, nothing is drawn in 630~639
+ dirtyRects.insert(_manager->alignRect(_xOffset, 0, _xOffset + srcSurface.w, srcSurface.h));
- cursor.reset();
+ cursor.reset(&srcSurface, _xOffset);
fullRedraw = true;
} else {
- dirtyRects.insert(rect);
+ const Common::Rect alignedRect = _manager->alignRect(x + _xOffset, y, x + _xOffset + w, y + h);
+
+ dirtyRects.insert(alignedRect);
- // do it now to avoid checking in AtariGraphicsManager::updateScreenInternal()
- cursor.flushBackground(directRendering ? Graphics::Surface() : srcSurface, rect);
+ // Check whether the cursor background intersects the dirty rect. Has to be done here,
+ // before the actual drawing (especially in case of direct rendering). There's one more
+ // check in AtariGraphicsManager::updateScreenInternal for the case when there are no
+ // dirty rectangles but the cursor itself has changed.
+ const Common::Rect cursorBackgroundRect = cursor.flushBackground(alignedRect, directRendering);
+ if (!cursorBackgroundRect.isEmpty()) {
+ dirtyRects.insert(cursorBackgroundRect);
+ }
}
}
diff --git a/backends/graphics/atari/atari-screen.h b/backends/graphics/atari/atari-screen.h
index abf1b156f7c..2cd49e0d8aa 100644
--- a/backends/graphics/atari/atari-screen.h
+++ b/backends/graphics/atari/atari-screen.h
@@ -63,9 +63,9 @@ struct Screen {
Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
~Screen();
- void reset(int width, int height, int bitsPerPixel, bool resetCursorPosition);
+ void reset(int width, int height, int bitsPerPixel, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition);
// must be called before any rectangle drawing
- void addDirtyRect(const Graphics::Surface &srcSurface, const Common::Rect &rect, bool directRendering);
+ void addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering);
void clearDirtyRects() {
dirtyRects.clear();
@@ -98,6 +98,7 @@ private:
const AtariGraphicsManager *_manager;
Graphics::Surface _offsettedSurf;
+ int _xOffset = 0;
};
#endif // BACKENDS_GRAPHICS_ATARI_SCREEN_H
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index 597001fab2d..62e9705d6a7 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -66,6 +66,9 @@
*/
#include "backends/fs/posix/posix-fs-factory.h"
+bool g_unalignedPitch = false;
+bool g_gameEngineActive = false;
+
extern "C" void atari_kbdvec(void *);
extern "C" void atari_mousevec(void *);
typedef void (*KBDVEC)(void *);
@@ -347,6 +350,45 @@ void OSystem_Atari::initBackend() {
BaseBackend::initBackend();
}
+void OSystem_Atari::engineInit() {
+ //atari_debug("engineInit");
+
+ g_gameEngineActive = true;
+
+ const Common::ConfigManager::Domain *activeDomain = ConfMan.getActiveDomain();
+ assert(activeDomain);
+
+ // FIXME: Some engines are too bound to linear surfaces that it is very
+ // hard to repair them. So instead of polluting the engine with
+ // Surface::init() & delete[] Surface::getPixels() just use this hack.
+ const Common::String engineId = activeDomain->getValOrDefault("engineid");
+ const Common::String gameId = activeDomain->getValOrDefault("gameid");
+
+ atari_debug("checking %s/%s", engineId.c_str(), gameId.c_str());
+
+ if (engineId == "composer"
+ || engineId == "hypno"
+ || engineId == "mohawk"
+ || engineId == "parallaction"
+ || engineId == "private"
+ || (engineId == "sci"
+ && (gameId == "phantasmagoria" || gameId == "shivers"))
+ || engineId == "sherlock"
+ || engineId == "teenagent"
+ || engineId == "tsage") {
+ g_unalignedPitch = true;
+ } else {
+ g_unalignedPitch = false;
+ }
+}
+
+void OSystem_Atari::engineDone() {
+ //atari_debug("engineDone");
+
+ g_gameEngineActive = false;
+ g_unalignedPitch = false;
+}
+
Common::MutexInternal *OSystem_Atari::createMutex() {
return new NullMutexInternal();
}
@@ -468,6 +510,8 @@ void OSystem_Atari::update() {
inTimer = false;
} else {
const Common::ConfigManager::Domain *activeDomain = ConfMan.getActiveDomain();
+ assert(activeDomain);
+
warning("%s/%s calls update() from timer",
activeDomain->getValOrDefault("engineid").c_str(),
activeDomain->getValOrDefault("gameid").c_str());
diff --git a/backends/platform/atari/osystem_atari.h b/backends/platform/atari/osystem_atari.h
index 6f428a64859..c3be4d8e1a6 100644
--- a/backends/platform/atari/osystem_atari.h
+++ b/backends/platform/atari/osystem_atari.h
@@ -31,6 +31,9 @@ public:
void initBackend() override;
+ void engineInit() override;
+ void engineDone() override;
+
Common::MutexInternal *createMutex() override;
uint32 getMillis(bool skipRecord = false) override;
void delayMillis(uint msecs) override;
diff --git a/backends/platform/atari/readme.txt b/backends/platform/atari/readme.txt
index 5fea469f3c2..63adeeefc33 100644
--- a/backends/platform/atari/readme.txt
+++ b/backends/platform/atari/readme.txt
@@ -479,6 +479,10 @@ Known issues
- point the extra path to the folder with *.wav files (or copy its content
where monkey.00? files are located)
+- Phantasmagoria, KQ7 (and other SCI32 games) require Single buffering (or
+ Direct rendering with SuperVidel) due to its unusual cursor rendering
+ approach.
+
- following engines have been explicitly disabled:
- Cine (2 games)
- incompatible with other engines / prone to freezes
diff --git a/backends/platform/atari/readme.txt.in b/backends/platform/atari/readme.txt.in
index 30083a4a8e1..c3bd62c9270 100644
--- a/backends/platform/atari/readme.txt.in
+++ b/backends/platform/atari/readme.txt.in
@@ -479,6 +479,10 @@ Known issues
- point the extra path to the folder with *.wav files (or copy its content
where monkey.00? files are located)
+- Phantasmagoria, KQ7 (and other SCI32 games) require Single buffering (or
+ Direct rendering with SuperVidel) due to its unusual cursor rendering
+ approach.
+
- following engines have been explicitly disabled:
- Cine (2 games)
- incompatible with other engines / prone to freezes
diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index 40753637820..02ba8a6fe88 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -84,8 +84,9 @@ void unlockSuperBlitter() {
#endif
}
-// see atari-graphics.cpp
+// see osystem-atari.cpp
extern bool g_unalignedPitch;
+// see atari-graphics.cpp
extern mspace g_mspace;
namespace Graphics {
Commit: 583660fb4cb4561f8980448a89763775359be416
https://github.com/scummvm/scummvm/commit/583660fb4cb4561f8980448a89763775359be416
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-04-20T21:40:32+02:00
Commit Message:
BACKENDS: ATARI: Fix crash with certain audio settings
E.g. 8195 Hz/2048 samples in KQ7 would lead to crash.
Changed paths:
backends/mixer/atari/atari-mixer.cpp
diff --git a/backends/mixer/atari/atari-mixer.cpp b/backends/mixer/atari/atari-mixer.cpp
index d7bc2c63f61..82baf1c2308 100644
--- a/backends/mixer/atari/atari-mixer.cpp
+++ b/backends/mixer/atari/atari-mixer.cpp
@@ -107,8 +107,8 @@ void AtariMixerManager::init() {
}
// don't use the recommended number of samples
- obtained.samples = desired.samples;
obtained.size = obtained.size * desired.samples / obtained.samples;
+ obtained.samples = desired.samples;
_outputRate = obtained.frequency;
_outputChannels = obtained.channels;
More information about the Scummvm-git-logs
mailing list