[Scummvm-git-logs] scummvm master -> eb64b14b81a723b3b692f95e1179f28356594e67

mikrosk noreply at scummvm.org
Wed Jun 25 21:51:02 UTC 2025


This automated email contains information about 17 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
e75b607579 JANITORIAL: Correct indentation
757ae0f58d JANITORIAL: Clarify DisposablePtr::reset()
f08bba77a8 JANITORIAL: Silence a few warnings
1bbd298799 BACKENDS: ATARI: Remove some .dat files
d452beff82 BACKENDS: ATARI: Remove g_unalignedPitch workaround
28507ee8a7 BACKENDS: ATARI: Cleanup fillScreen()
b3074272da BACKENDS: ATARI: Separate SuperVidel code
3dc861cf12 GRAPHICS: ATARI: Add specialized keyBlitLogic
3dd96ec7c5 BACKENDS: ATARI: Use hardware-accelerated cursor blitting
fbbecd55f3 GRAPHICS: Make Graphics::PixelFormat::createFormatCLUT8 constexpr
0520570a7b BACKENDS: ATARI: Move getBitsPerPixel from AtariGraphicsManager to AtariSurface
ee437e2a42 BACKENDS: ATARI: Move alignRect from AtariGraphicsManager to AtariSurface
f27f045aac BACKENDS: ATARI: Remove references to AtariGraphicsManager from Screen and Cursor
e575d1360e BACKENDS: ATARI: Make purpose of _xOffset more explicit
3f47c7a8ce BACKENDS: ATARI: Let Cursor access only AtariSurface instead of Screen
25d125bdc0 BACKENDS: ATARI: Avoid redefinition warning
eb64b14b81 BACKENDS: ATARI: Implement proper cursor clipping


Commit: e75b607579e0243f9eae672f853362c3e980832c
    https://github.com/scummvm/scummvm/commit/e75b607579e0243f9eae672f853362c3e980832c
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
JANITORIAL: Correct indentation

Changed paths:
    backends/graphics/atari/atari-c2p-asm.S


diff --git a/backends/graphics/atari/atari-c2p-asm.S b/backends/graphics/atari/atari-c2p-asm.S
index bab5460f58e..5c0f9a9e366 100644
--- a/backends/graphics/atari/atari-c2p-asm.S
+++ b/backends/graphics/atari/atari-c2p-asm.S
@@ -36,13 +36,13 @@
 | void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
 SYM(asm_c2p1x1_8):
 #ifdef __FASTCALL__
-									| a0: chunky
-	move.l	a1,d0					| chunky end
-	move.l	4(sp),a1				| screen
+						| a0: chunky
+	move.l	a1,d0				| chunky end
+	move.l	4(sp),a1			| screen
 #else
-	move.l	(4,sp),a0				| chunky
-	move.l	(8,sp),d0				| chunky end
-	move.l	(12,sp),a1				| screen
+	move.l	(4,sp),a0			| chunky
+	move.l	(8,sp),d0			| chunky end
+	move.l	(12,sp),a1			| screen
 #endif
 	movem.l	d2-d7/a2-a6,-(sp)
 	move.l	d0,a2
@@ -238,26 +238,25 @@ c2p1x1_8_start:
 
 | void asm_c2p1x1_8_tt(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen, uint32 screenPitch);
 SYM(asm_c2p1x1_8_tt):
-	movem.l	d2-d7/a2-a6,-(sp)			| 6 + 5 = 11 longs
+	movem.l	d2-d7/a2-a6,-(sp)		| 6 + 5 = 11 longs
 
 #ifdef __FASTCALL__
-										| a0: chunky
-	move.l	a1,a2						| a2: chunky end
-	move.l	(11*4+4,sp),a1				| a1: screen
-										| d0.l: screen pitch (double width)
+						| a0: chunky
+	move.l	a1,a2				| a2: chunky end
+	move.l	(11*4+4,sp),a1			| a1: screen
+						| d0.l: screen pitch (double width)
 #else
-	move.l	(11*4+4,sp),a0				| a0: chunky
-	move.l	(11*4+8,sp),a2				| a2: chunky end
-	move.l	(11*4+12,sp),a1				| a1: screen
-	move.l	(11*4+16,sp),d0				| d0.l: screen pitch (double width)
+	move.l	(11*4+4,sp),a0			| a0: chunky
+	move.l	(11*4+8,sp),a2			| a2: chunky end
+	move.l	(11*4+12,sp),a1			| a1: screen
+	move.l	(11*4+16,sp),d0			| d0.l: screen pitch (double width)
 #endif
-
 	move.l	sp,old_sp
 
 	move.l	d0,screen_pitch
 
 	lsr.l	#1,d0
-	lea	(a1,d0.l),a7				| a7: end of first dst line
+	lea	(a1,d0.l),a7			| a7: end of first dst line
 
 	move.l	d0,screen_offset
 
@@ -460,28 +459,27 @@ c2p1x1_8_tt_start:
 
 | void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
 SYM(asm_c2p1x1_8_rect):
-	movem.l	d2-d7/a2-a6,-(sp)			| 6 + 5 = 11 longs
+	movem.l	d2-d7/a2-a6,-(sp)		| 6 + 5 = 11 longs
 
 #ifdef __FASTCALL__
-										| a0: chunky
+						| a0: chunky
 	move.l	a1,chunky_end
-										| d0.l: chunky width
-	move.l	(11*4+4,sp),a1				| a1: screen
-	exg		d1,d2						| d2.l: chunky pitch
-										| d1.l: screen pitch
+						| d0.l: chunky width
+	move.l	(11*4+4,sp),a1			| a1: screen
+	exg	d1,d2				| d2.l: chunky pitch
+						| d1.l: screen pitch
 #else
-	move.l	(11*4+4,sp),a0				| a0: chunky
+	move.l	(11*4+4,sp),a0			| a0: chunky
 	move.l	(11*4+8,sp),chunky_end
-	move.l	(11*4+12,sp),d0				| d0.l: chunky width
-	move.l	(11*4+16,sp),d2				| d2.l: chunky pitch
-	move.l	(11*4+20,sp),a1				| a1: screen
-	move.l	(11*4+24,sp),d1				| d1.l: screen pitch
+	move.l	(11*4+12,sp),d0			| d0.l: chunky width
+	move.l	(11*4+16,sp),d2			| d2.l: chunky pitch
+	move.l	(11*4+20,sp),a1			| a1: screen
+	move.l	(11*4+24,sp),d1			| d1.l: screen pitch
 #endif
-
 	move.l	sp,old_sp
 
-	lea	(a0,d0.l),a2				| a2: end of first src line
-	lea	(a1,d0.l),a7				| a7: end of first dst line
+	lea	(a0,d0.l),a2			| a2: end of first src line
+	lea	(a1,d0.l),a7			| a7: end of first dst line
 
 	move.l	d1,screen_pitch
 
@@ -604,7 +602,7 @@ c2p1x1_8_rect_pix16:
 	| b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
 	| b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
 
-	cmp.l	a1,a7					| end of dst line?
+	cmp.l	a1,a7				| end of dst line?
 	bne.s	c2p1x1_8_rect_start
 
 	add.l	(screen_offset,pc),a1
@@ -677,7 +675,7 @@ c2p1x1_8_rect_start:
 	move.l	d1,a4
 	move.l	d3,a3
 
-	cmp.l	a0,a2					| end of src line?
+	cmp.l	a0,a2				| end of src line?
 	bne	c2p1x1_8_rect_pix16
 
 	cmp.l	(chunky_end,pc),a2
@@ -702,13 +700,13 @@ c2p1x1_8_rect_done:
 | void asm_c2p1x1_4(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
 SYM(asm_c2p1x1_4):
 #ifdef __FASTCALL__
-									| a0: chunky
-	move.l	a1,d0					| chunky end
-	move.l	4(sp),a1				| screen
+						| a0: chunky
+	move.l	a1,d0				| chunky end
+	move.l	4(sp),a1			| screen
 #else
-	move.l	(4,sp),a0				| chunky
-	move.l	(8,sp),d0				| chunky end
-	move.l	(12,sp),a1				| screen
+	move.l	(4,sp),a0			| chunky
+	move.l	(8,sp),d0			| chunky end
+	move.l	(12,sp),a1			| screen
 #endif
 	movem.l	d2-d7/a2-a6,-(sp)
 	move.l	d0,a2
@@ -803,31 +801,30 @@ c2p1x1_4_start:
 
 | void asm_c2p1x1_4_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
 SYM(asm_c2p1x1_4_rect):
-	movem.l	d2-d7/a2-a6,-(sp)			| 6 + 5 = 11 longs
+	movem.l	d2-d7/a2-a6,-(sp)		| 6 + 5 = 11 longs
 
 #ifdef __FASTCALL__
-										| a0: chunky
+						| a0: chunky
 	move.l	a1,chunky_end
-										| d0.l: chunky width
-	move.l	(11*4+4,sp),a1				| a1: screen
-	exg		d1,d2						| d2.l: chunky pitch
-										| d1.l: screen pitch
+						| d0.l: chunky width
+	move.l	(11*4+4,sp),a1			| a1: screen
+	exg	d1,d2				| d2.l: chunky pitch
+						| d1.l: screen pitch
 #else
-	move.l	(11*4+4,sp),a0				| a0: chunky
+	move.l	(11*4+4,sp),a0			| a0: chunky
 	move.l	(11*4+8,sp),chunky_end
-	move.l	(11*4+12,sp),d0				| d0.l: chunky width
-	move.l	(11*4+16,sp),d2				| d2.l: chunky pitch
-	move.l	(11*4+20,sp),a1				| a1: screen
-	move.l	(11*4+24,sp),d1				| d1.l: screen pitch
+	move.l	(11*4+12,sp),d0			| d0.l: chunky width
+	move.l	(11*4+16,sp),d2			| d2.l: chunky pitch
+	move.l	(11*4+20,sp),a1			| a1: screen
+	move.l	(11*4+24,sp),d1			| d1.l: screen pitch
 #endif
-
 	move.l	sp,old_sp
 
-	move.l	d0,d3					| d3.l: screen width
-	lsr.l	#1,d3					|
+	move.l	d0,d3				| d3.l: screen width
+	lsr.l	#1,d3				|
 
-	lea	(a0,d0.l),a2				| a2: end of first src line
-	lea	(a1,d3.l),a7				| a7: end of first dst line
+	lea	(a0,d0.l),a2			| a2: end of first src line
+	lea	(a1,d3.l),a7			| a7: end of first dst line
 
 	move.l	d1,screen_pitch
 
@@ -865,7 +862,7 @@ c2p1x1_4_rect_pix16:
 	or.l	d3,d1
 	move.l	a6,(a1)+
 
-	cmp.l	a1,a7					| end of dst line?
+	cmp.l	a1,a7				| end of dst line?
 	bne.s	c2p1x1_4_rect_start
 
 	add.l	(screen_offset,pc),a1
@@ -924,7 +921,7 @@ c2p1x1_4_rect_start:
 	move.l	d1,a5
 	move.l	d0,a6
 
-	cmp.l	a0,a2					| end of src line?
+	cmp.l	a0,a2				| end of src line?
 	bne.s	c2p1x1_4_rect_pix16
 
 	cmp.l	(chunky_end,pc),a2


Commit: 757ae0f58d548d1ef3780821a2b3295b0e9d7b94
    https://github.com/scummvm/scummvm/commit/757ae0f58d548d1ef3780821a2b3295b0e9d7b94
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
JANITORIAL: Clarify DisposablePtr::reset()

Changed paths:
    common/ptr.h


diff --git a/common/ptr.h b/common/ptr.h
index a33edcb1107..dd08d13e027 100644
--- a/common/ptr.h
+++ b/common/ptr.h
@@ -602,7 +602,7 @@ public:
 	}
 
 	/**
-	 * Resets the pointer with the new value. Old object will be destroyed
+	 * Resets the pointer with the new value. Old object will be destroyed.
 	 */
 	void reset(PointerType o = nullptr) {
 		DL()(_pointer);
@@ -680,7 +680,7 @@ public:
 	bool operator_bool() const { return _pointer != nullptr; }
 
 	/**
-	 * Resets the pointer with the new value. Old object will be destroyed
+	 * Resets the pointer with the new value. Old object will be destroyed if flagged as disposable.
 	 */
 	void reset(PointerType o, DisposeAfterUse::Flag dispose) {
 		if (_dispose) DL()(_pointer);
@@ -690,7 +690,7 @@ public:
 	}
 
 	/**
-	 * Clears the pointer. Old object will be destroyed
+	 * Clears the pointer. Old object will be destroyed if flagged as disposable.
 	 */
 	void reset() {
 		reset(nullptr, DisposeAfterUse::NO);


Commit: f08bba77a85595bf096249adbca326267fd56498
    https://github.com/scummvm/scummvm/commit/f08bba77a85595bf096249adbca326267fd56498
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
JANITORIAL: Silence a few warnings

This shaves off 250 out of 320 KB stderr log when asserts are
disabled.

Changed paths:
    engines/mm/xeen/resources.h


diff --git a/engines/mm/xeen/resources.h b/engines/mm/xeen/resources.h
index a3bab477052..ccbc8a2ae3c 100644
--- a/engines/mm/xeen/resources.h
+++ b/engines/mm/xeen/resources.h
@@ -63,12 +63,14 @@ class Resources {
 		void syncStrings(const char **str, int count) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count, 0, 0, 0));
+			(void)tag;
 			for (int idx = 0; idx < count; ++idx)
 				syncString(str[idx]);
 		}
 		void syncStrings2D(const char **str, int count1, int count2) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count1, count2, 0, 0));
+			(void)tag;
 			for (int idx = 0; idx < count1 * count2; ++idx)
 				syncString(str[idx]);
 		}
@@ -78,30 +80,35 @@ class Resources {
 		void syncNumbers(int *vals, int count) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count, 0, 0, 0));
+			(void)tag;
 			for (int idx = 0; idx < count; ++idx)
 				vals[idx] = readSint32LE();
 		}
 		void syncNumbers2D(int *vals, int count1, int count2) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count1, count2, 0, 0));
+			(void)tag;
 			for (int idx = 0; idx < count1 * count2; ++idx)
 				vals[idx] = readSint32LE();
 		}
 		void syncNumbers3D(int *vals, int count1, int count2, int count3) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count1, count2, count3, 0));
+			(void)tag;
 			for (int idx = 0; idx < count1 * count2 * count3; ++idx)
 				vals[idx] = readSint32LE();
 		}
 		void syncNumbers4D(int *vals, int count1, int count2, int count3, int count4) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count1, count2, count3, count4));
+			(void)tag;
 			for (int idx = 0; idx < count1 * count2 * count3 * count4; ++idx)
 				vals[idx] = readSint32LE();
 		}
 		void syncBytes2D(byte *vals, int count1, int count2) {
 			uint tag = readUint32LE();
 			assert(tag == MKTAG(count1, count2, 0, 0));
+			(void)tag;
 			read(vals, count1 * count2);
 		}
 	};


Commit: 1bbd29879914e3cef06e78f6fc621a66d9ab4d40
    https://github.com/scummvm/scummvm/commit/1bbd29879914e3cef06e78f6fc621a66d9ab4d40
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
BACKENDS: ATARI: Remove some .dat files

Those are not used in Atari port and just take space and annoy users
with their long filenames.

Changed paths:
    backends/platform/atari/build-release.sh
    backends/platform/atari/build-release030.sh


diff --git a/backends/platform/atari/build-release.sh b/backends/platform/atari/build-release.sh
index 1e6d591d1d4..59d2484b112 100755
--- a/backends/platform/atari/build-release.sh
+++ b/backends/platform/atari/build-release.sh
@@ -56,7 +56,7 @@ ${PLATFORM}-nm -C dist-generic/scummvm/scummvm.ttp | grep -vF ' .L' | grep ' [Tt
 ${PLATFORM}-strip -s dist-generic/scummvm/scummvm.ttp
 
 # remove unused files; absent gui-icons.dat massively speeds up startup time (used for the grid mode)
-rm dist-generic/scummvm/data/{achievements,encoding,gui-icons,macgui,shaders}.dat
+rm dist-generic/scummvm/data/{achievements,classicmacfonts,encoding,gui-icons,hadesch_translations,macgui,prince_translation,shaders}.dat
 
 # rename remaining files still not fitting into the 8+3 limit (this has to be supported by the backend, too)
 mv dist-generic/scummvm/data/cryomni3d.dat dist-generic/scummvm/data/cryomni3.dat
diff --git a/backends/platform/atari/build-release030.sh b/backends/platform/atari/build-release030.sh
index 8391f3619ae..4f35abe3ab3 100755
--- a/backends/platform/atari/build-release030.sh
+++ b/backends/platform/atari/build-release030.sh
@@ -58,7 +58,7 @@ ${PLATFORM}-nm -C dist-generic/scummvm/scummvm.ttp | grep -vF ' .L' | grep ' [Tt
 ${PLATFORM}-strip -s dist-generic/scummvm/scummvm.ttp
 
 # remove unused files
-rm dist-generic/scummvm/data/*.zip dist-generic/scummvm/data/{achievements,encoding,gui-icons,macgui,shaders}.dat
+rm dist-generic/scummvm/data/*.zip dist-generic/scummvm/data/{achievements,classicmacfonts,encoding,gui-icons,macgui,shaders}.dat
 
 # rename remaining files still not fitting into the 8+3 limit (this has to be supported by the backend, too)
 mv dist-generic/scummvm/data/supernova.dat dist-generic/scummvm/data/supernov.dat


Commit: d452beff828945bcfca58de162e7d28c9875a6f4
    https://github.com/scummvm/scummvm/commit/d452beff828945bcfca58de162e7d28c9875a6f4
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
BACKENDS: ATARI: Remove g_unalignedPitch workaround

It causes more harm than good and I don't think it helps with
performance that much either. Its only semi-valid use case was C2P
direct rendering for sprites (which nobody uses). However, direct
rendering in its current form is about to be removed in a near future,
so...

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-graphics.cpp
    backends/platform/atari/osystem_atari.cpp
    graphics/blit/blit-atari.cpp


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 5637c07d6d6..1cc488103b4 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -140,12 +140,7 @@ void Cursor::convertSurfaceTo(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
-		g_unalignedPitch = old_unalignedPitch;
 	}
 
 	const int srcRectWidth = _srcRect.width();
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 77f4e462d26..70907377ca0 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -431,17 +431,13 @@ 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 (((hasPendingGraphicsMode && _pendingState.mode == kDirectRendering)
 				|| (!hasPendingGraphicsMode && _currentState.mode == kDirectRendering))
-			&& (_pendingState.width % 16 != 0 || g_unalignedPitch)
+			&& _pendingState.width % 16 != 0
 			&& !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
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index d6d0b6b8b64..663a8a47cd4 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -66,7 +66,6 @@
  */
 #include "backends/fs/atari/atari-fs-factory.h"
 
-bool g_unalignedPitch = false;
 bool g_gameEngineActive = false;
 
 extern "C" void atari_kbdvec(void *);
@@ -354,40 +353,12 @@ 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 == "dgds"
-		|| 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() {
diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index 62fd61cd0e7..e4d807a2e12 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -92,8 +92,6 @@ void unlockSuperBlitter() {
 #endif
 }
 
-// see osystem-atari.cpp
-extern bool g_unalignedPitch;
 // see atari-graphics.cpp
 extern mspace g_mspace;
 
@@ -110,10 +108,7 @@ void Surface::create(int16 width, int16 height, const PixelFormat &f) {
 	w = width;
 	h = height;
 	format = f;
-	// align pitch to a 16-byte boundary for a possible C2P conversion
-	pitch = g_unalignedPitch
-		? w * format.bytesPerPixel
-		: (w * format.bytesPerPixel + ALIGN - 1) & (-ALIGN);
+	pitch = w * format.bytesPerPixel;
 
 	if (width && height) {
 #ifdef USE_SV_BLITTER


Commit: 28507ee8a7aae41ec227dd5c5cf9409f269aab23
    https://github.com/scummvm/scummvm/commit/28507ee8a7aae41ec227dd5c5cf9409f269aab23
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
BACKENDS: ATARI: Cleanup fillScreen()

The workaround for Eco Quest was misguided, I was updating whole screen
every time!

Changed paths:
    backends/graphics/atari/atari-graphics.cpp


diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 70907377ca0..6f7020952e1 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -611,27 +611,27 @@ void AtariGraphicsManager::unlockScreen() {
 void AtariGraphicsManager::fillScreen(uint32 col) {
 	atari_debug("fillScreen: %d", col);
 
-	Graphics::Surface *screen = lockScreen();
+	Graphics::Surface &dstSurface = *lockScreen();
 
-	screen->fillRect(Common::Rect(screen->w, screen->h), col);
+	addDirtyRectToScreens(
+		dstSurface,
+		0, 0, dstSurface.w, dstSurface.h,
+		_currentState.mode == kDirectRendering);
 
-	unlockScreen();
+	dstSurface.fillRect(Common::Rect(dstSurface.w, dstSurface.h), col);
 }
 
 void AtariGraphicsManager::fillScreen(const Common::Rect &r, uint32 col) {
 	//atari_debug("fillScreen: %dx%d %d", r.width(), r.height(), col);
 
-	Graphics::Surface *screen = lockScreen();
+	Graphics::Surface &dstSurface = *lockScreen();
 
-	if (r.width() == 1 && r.height() == 1) {
-		// handle special case for e.g. Eco Quest's intro
-		byte *ptr = (byte *)screen->getBasePtr(r.left, r.top);
-		*ptr = col;
-	} else {
-		screen->fillRect(r, col);
-	}
+	addDirtyRectToScreens(
+		dstSurface,
+		r.left, r.top, r.width(), r.height(),
+		_currentState.mode == kDirectRendering);
 
-	unlockScreen();
+	dstSurface.fillRect(r, col);
 }
 
 void AtariGraphicsManager::updateScreen() {
@@ -1017,10 +1017,7 @@ bool AtariGraphicsManager::notifyEvent(const Common::Event &event) {
 		if (isOverlayVisible()) {
 			debug("Return to launcher from overlay");
 			// clear work screen: this is needed if *next* game shows an error upon startup
-			Graphics::Surface &surf = _currentState.mode == kDirectRendering
-				? *_screen[kFrontBuffer]->offsettedSurf
-				: _chunkySurfaceOffsetted;
-			surf.fillRect(Common::Rect(surf.w, surf.h), 0);
+			fillScreen(0);
 
 			_ignoreHideOverlay = true;
 			// gui manager would want to hide overlay, set game cursor etc


Commit: b3074272daef0a0a0a739db5a4fec71ea37354d0
    https://github.com/scummvm/scummvm/commit/b3074272daef0a0a0a739db5a4fec71ea37354d0
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
BACKENDS: ATARI: Separate SuperVidel code

- Introduce AtariSurface: a surface which represents either a
  bitplane-based or pixel-based surface (on SuperVidel, as an inherited
  SuperVidelSurface). Screen::surf / Screen::offsettedSurf are its
  instances.

- Graphics::Surface::create / free now handle all Atari-related surfaces
  via dlmalloc: ST RAM (TT/Falcon), VRAM (SuperVidel - 0xA0xxxxxx) and
  VRAM for generic surfaces (SuperBlitter - 0xA1xxxxxx or ST/TT RAM).
  This allowed me to remove all the hacky stuff from atari-graphics and
  atari-superblitter.h.

- blit-atari.cpp now contains only blitting code
  (SuperBlitter/move16/fallback), SV code is in
  atari-supervidel.{cpp,h}.

- Take advantage of Common::ScopedPtr and Graphics::ManagedSurface's
  dispose flag for Screen::surf as well Graphics::ManagedSurface's
  ownership for Screen::offsettedSurf.

- Improve recoverability if an error/assert happens in
  AtariGraphicsManager's c-tor/d-tor.

Changed paths:
  A backends/graphics/atari/atari-supervidel.cpp
  A backends/graphics/atari/atari-supervidel.h
  A backends/graphics/atari/atari-surface.cpp
  A backends/graphics/atari/atari-surface.h
  R backends/graphics/atari/atari-graphics-superblitter.h
  R backends/graphics/atari/atari-graphics-supervidel.h
  R backends/graphics/atari/atari-graphics-videl.h
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-graphics.h
    backends/graphics/atari/atari-pendingscreenchanges.cpp
    backends/graphics/atari/atari-pendingscreenchanges.h
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-screen.h
    backends/module.mk
    backends/platform/atari/osystem_atari.cpp
    backends/platform/atari/osystem_atari.h
    graphics/blit/blit-atari.cpp
    graphics/surface.cpp


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 1cc488103b4..7e04cf00341 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -21,20 +21,17 @@
 
 #include "atari-cursor.h"
 
-#include <cassert>
-
 #include "atari-graphics.h"
 #include "atari-screen.h"
+#include "atari-supervidel.h"
+#include "atari-surface.h"
 //#include "backends/platform/atari/atari-debug.h"
 
 byte Cursor::_palette[256*3] = {};
 
-Cursor::Cursor(const AtariGraphicsManager *manager, const Screen *screen, int x, int y)
+Cursor::Cursor(const AtariGraphicsManager *manager, const Screen *screen)
 		: _manager(manager)
-		, _parentScreen(screen)
-		, _boundingSurf(screen->offsettedSurf)
-		, _x(x)
-		, _y(y) {
+		, _parentScreen(screen) {
 }
 
 void Cursor::update() {
@@ -219,7 +216,7 @@ void Cursor::saveBackground() {
 
 	// 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 Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
 
 	//atari_debug("Cursor::saveBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
 
@@ -234,27 +231,27 @@ void Cursor::saveBackground() {
 }
 
 void Cursor::draw() {
-	Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
-	const int dstBitsPerPixel     = _manager->getBitsPerPixel(dstSurface.format);
+	auto &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());
 
 	if (_surfaceChanged || _srcRect.width() != _previousSrcRect.width()) {
 		_previousSrcRect = _srcRect;
 
-		// 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;
-			surf.init(
-				_surface.w,
-				_surface.h,
-				_surface.pitch * dstBitsPerPixel / 8,	// 4bpp is not byte per pixel anymore
-				_surface.getPixels(),
-				_surface.format);
-			_manager->copyRectToSurface(
-				surf, _surface,
+
+		if (!g_hasSuperVidel) {
+			// C2P in-place (TODO: merge with convertSurfaceTo)
+			AtariSurface surf(dstBitsPerPixel);
+			surf.w = _surface.w;
+			surf.h = _surface.h;
+			surf.pitch = _surface.pitch * dstBitsPerPixel / 8;	// 4bpp is not byte per pixel anymore
+			surf.setPixels(_surface.getPixels());
+			surf.format = _surface.format;
+
+			surf.copyRectToSurface(
+				_surface,
 				0, 0,
 				Common::Rect(_surface.w, _surface.h));
 		}
@@ -262,8 +259,7 @@ void Cursor::draw() {
 
 	// don't use _srcRect.right as 'x2' as this must be aligned first
 	// (_surface.w is recalculated thanks to convertSurfaceTo())
-	_manager->drawMaskedSprite(
-		dstSurface,
+	dstSurface.drawMaskedSprite(
 		_surface, _surfaceMask,
 		_dstRect.left + _xOffset, _dstRect.top,
 		Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
@@ -281,9 +277,9 @@ void Cursor::restoreBackground() {
 
 	// 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;
+	Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf->surfacePtr();
 
-	// restore native pixels (i.e. bitplanes)
+	// restore native bitplanes or pixels, so it must be a Graphics::Surface to copy to
 	dstSurface.copyRectToSurface(
 		_savedBackground,
 		_savedRect.left, _savedRect.top,
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 7413182e549..3bbb56b4ecc 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -22,8 +22,6 @@
 #ifndef BACKENDS_GRAPHICS_ATARI_CURSOR_H
 #define BACKENDS_GRAPHICS_ATARI_CURSOR_H
 
-#include "common/rect.h"
-#include "common/scummsys.h"
 #include "graphics/surface.h"
 //#include "backends/platform/atari/atari-debug.h"
 
@@ -37,7 +35,7 @@ struct Screen;
 // These always get updates by ScummVM, no need to differentiate between engines and the overlay.
 
 struct Cursor {
-	Cursor(const AtariGraphicsManager *manager, const Screen *screen, int x, int y);
+	Cursor(const AtariGraphicsManager *manager, const Screen *screen);
 
 	void reset(const Graphics::Surface *boundingSurf, int xOffset) {
 		_boundingSurf = boundingSurf;
@@ -108,7 +106,7 @@ private:
 
 	const AtariGraphicsManager *_manager;
 	const Screen *_parentScreen;
-	const Graphics::Surface *_boundingSurf;
+	const Graphics::Surface *_boundingSurf = nullptr;
 	int _xOffset = 0;
 
 	bool _positionChanged = true;
@@ -116,8 +114,8 @@ private:
 	bool _visibilityChanged = false;
 
 	bool _visible = false;
-	int _x;
-	int _y;
+	int _x = 0;
+	int _y = 0;
 	bool _outOfScreen = true;
 	Common::Rect _srcRect;
 	Common::Rect _dstRect;
diff --git a/backends/graphics/atari/atari-graphics-supervidel.h b/backends/graphics/atari/atari-graphics-supervidel.h
deleted file mode 100644
index 9a34f3d24a8..00000000000
--- a/backends/graphics/atari/atari-graphics-supervidel.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
-#define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
-
-#ifdef USE_SUPERVIDEL
-
-#include "backends/graphics/atari/atari-graphics.h"
-
-#include <mint/osbind.h>
-
-#ifdef USE_SV_BLITTER
-#include <mint/trap14.h>
-#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
-#define ct60_vmalloc(value) ct60_vm(0, value)
-#define ct60_vmfree(value)  ct60_vm(1, value)
-
-#include "backends/platform/atari/dlmalloc.h"
-extern mspace g_mspace;
-#endif
-
-#include "backends/graphics/atari/atari-graphics-superblitter.h"
-#include "backends/platform/atari/atari-debug.h"
-#include "common/scummsys.h"
-
-class AtariSuperVidelManager : public AtariGraphicsManager {
-public:
-	AtariSuperVidelManager() {
-#ifdef USE_SV_BLITTER
-		atari_debug("SuperVidel FW Revision: %d, using %s", superVidelFwVersion, superVidelFwVersion >= 9
-			? "fast async FIFO" : "slower sync blitting");
-#else
-		atari_debug("SuperVidel FW Revision: %d, SuperBlitter not used", superVidelFwVersion);
-#endif
-		if (Supexec(hasSvRamBoosted))
-			atari_debug("SV_XBIOS has the pmmu boost enabled");
-		else
-			atari_warning("SV_XBIOS has the pmmu boost disabled, set 'pmmu_boost = true' in C:\\SV.INF");
-
-#ifdef USE_SV_BLITTER
-		size_t vramSize = ct60_vmalloc(-1) - (16 * 1024 * 1024);	// SV XBIOS seems to forget the initial 16 MB ST RAM mirror
-		_vramBase = vramSize > 0 ? (void *)ct60_vmalloc(vramSize) : nullptr;
-		if (_vramBase) {
-			g_mspace = create_mspace_with_base(_vramBase, vramSize, 0);
-			atari_debug("Allocated VRAM at %p (%ld bytes)", _vramBase, vramSize);
-		}
-
-		if (!g_mspace)
-			atari_warning("VRAM allocation failed");
-#endif
-		// using virtual methods so must be done here
-		allocateSurfaces();
-	}
-
-	~AtariSuperVidelManager() {
-		// using virtual methods so must be done here
-		freeSurfaces();
-
-#ifdef USE_SV_BLITTER
-		if (_vramBase) {
-			destroy_mspace(g_mspace);
-			g_mspace = nullptr;
-
-			ct60_vmfree(_vramBase);
-			_vramBase = nullptr;
-		}
-#endif
-	}
-
-private:
-	AtariMemAlloc getStRamAllocFunc() const override {
-		return [](size_t bytes) {
-			uintptr ptr = Mxalloc(bytes, MX_STRAM);
-
-			if (ptr != 0)
-				ptr |= 0xA0000000;
-
-			return (void *)ptr;
-		};
-	}
-	AtariMemFree getStRamFreeFunc() const override {
-		return [](void *ptr) { Mfree((uintptr)ptr & 0x00FFFFFF); };
-	}
-
-	void drawMaskedSprite(Graphics::Surface &dstSurface,
-						  const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
-						  int destX, int destY,
-						  const Common::Rect &subRect) const override {
-		assert(dstSurface.format == Graphics::PixelFormat::createFormatCLUT8());
-		assert(subRect.width() % 16 == 0);
-		assert(subRect.width() == srcSurface.w);
-
-		const byte *src = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
-		const uint16 *mask = (const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top);
-		byte *dst = (byte *)dstSurface.getBasePtr(destX, destY);
-
-		const int h = subRect.height();
-		const int w = subRect.width();
-		const int dstOffset = dstSurface.pitch - w;
-
-		for (int j = 0; j < h; ++j) {
-			for (int i = 0; i < w; i += 16, mask++) {
-				const uint16 m = *mask;
-
-				if (m == 0xFFFF) {
-					// all 16 pixels transparent
-					src += 16;
-					dst += 16;
-					continue;
-				}
-
-				for (int k = 0; k < 16; ++k) {
-					const uint16 bit = 1 << (15 - k);
-
-					if (m & bit) {
-						// transparent
-						src++;
-						dst++;
-					} else {
-						*dst++ = *src++;
-					}
-				}
-			}
-
-			dst += dstOffset;
-		}
-	}
-
-	static long hasSvRamBoosted() {
-		register long ret __asm__ ("d0") = 0;
-
-		__asm__ volatile(
-		"\tmovec	%%itt0,%%d1\n"
-		"\tcmp.l	#0xA007E060,%%d1\n"
-		"\tbne.s	1f\n"
-
-		"\tmovec	%%dtt0,%%d1\n"
-		"\tcmp.l	#0xA007E060,%%d1\n"
-		"\tbne.s	1f\n"
-
-		"\tmoveq	#1,%%d0\n"
-
-	"1:\n"
-		: "=g"(ret)	/* outputs */
-		:			/* inputs  */
-		: __CLOBBER_RETURN("d0") "d1", "cc"
-		);
-
-		return ret;
-	}
-
-#ifdef USE_SV_BLITTER
-	void *_vramBase = nullptr;
-#endif
-};
-
-#endif	// USE_SUPERVIDEL
-
-#endif
diff --git a/backends/graphics/atari/atari-graphics-videl.h b/backends/graphics/atari/atari-graphics-videl.h
deleted file mode 100644
index 15126436e67..00000000000
--- a/backends/graphics/atari/atari-graphics-videl.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef BACKENDS_GRAPHICS_ATARI_VIDEL_H
-#define BACKENDS_GRAPHICS_ATARI_VIDEL_H
-
-#include "backends/graphics/atari/atari-graphics.h"
-
-#include "backends/graphics/atari/atari-c2p-asm.h"
-#include "backends/graphics/atari/atari-graphics-asm.h"
-#include "common/system.h"
-
-class AtariVidelManager : public AtariGraphicsManager {
-public:
-	AtariVidelManager() {
-		// using virtual methods so must be done here
-		allocateSurfaces();
-	}
-
-	~AtariVidelManager() {
-		// using virtual methods so must be done here
-		freeSurfaces();
-	}
-
-private:
-	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*
-		// 2. (subRect.right, subRect.bottom) = even worse, end of the *next* line, not current one
-		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 * bitsPerPixel/8;
-
-		if (bitsPerPixel == 8) {
-			if (srcSurface.pitch == subRect.width()) {
-				if (srcSurface.pitch == dstSurface.pitch) {
-					asm_c2p1x1_8(pChunky, pChunkyEnd, pScreen);
-					return;
-				} else if (srcSurface.pitch == dstSurface.pitch/2) {
-                    asm_c2p1x1_8_tt(pChunky, pChunkyEnd, pScreen, dstSurface.pitch);
-					return;
-				}
-			}
-
-			asm_c2p1x1_8_rect(
-				pChunky, pChunkyEnd,
-				subRect.width(),
-				srcSurface.pitch,
-				pScreen,
-                dstSurface.pitch);
-		} else {
-            if (srcSurface.pitch == subRect.width() && srcSurface.pitch/2 == dstSurface.pitch) {
-				asm_c2p1x1_4(pChunky, pChunkyEnd, pScreen);
-				return;
-			}
-
-			asm_c2p1x1_4_rect(
-				pChunky, pChunkyEnd,
-				subRect.width(),
-				srcSurface.pitch,
-				pScreen,
-                dstSurface.pitch);
-		}
-	}
-
-	void drawMaskedSprite(Graphics::Surface &dstSurface,
-						  const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
-						  int destX, int destY,
-						  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 (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),
-				destX, destY,
-				dstSurface.pitch, subRect.width(), subRect.height());
-		}
-	}
-};
-
-#endif
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 6f7020952e1..bdabe154b56 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -29,22 +29,18 @@
 #include <mint/sysvars.h>
 
 #include "backends/platform/atari/atari-debug.h"
-#include "backends/platform/atari/dlmalloc.h"
 #include "backends/keymapper/action.h"
 #include "backends/keymapper/keymap.h"
 #include "common/config-manager.h"
 #include "common/str.h"
 #include "common/translation.h"
 #include "engines/engine.h"
-#include "graphics/blit.h"
 #include "gui/ThemeEngine.h"
 
-#include "atari-graphics-superblitter.h"
+#include "atari-surface.h"
 
 #define SCREEN_ACTIVE
 
-mspace g_mspace = nullptr;
-
 static const Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::createFormatCLUT8();
 static const Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
 static const Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
@@ -54,7 +50,7 @@ static void shrinkVidelVisibleArea() {
 	// In case of 320x240, the number is still 480 but data is fetched
 	// only for 240 lines so it doesn't make a difference to us.
 #ifdef SCREEN_ACTIVE
-	if (hasSuperVidel()) {
+	if (g_hasSuperVidel) {
 		const int vOffset = ((480 - 400) / 2) * 2;	// *2 because of half-lines
 
 		// VDB = VBE = VDB + paddding/2
@@ -83,11 +79,11 @@ static int s_shakeYOffset;
 static int s_aspectRatioCorrectionYOffset;
 static bool s_shrinkVidelVisibleArea;
 static bool s_setScreenOffsets;
-static Graphics::Surface *s_screenSurf;
+static AtariSurface *s_screenSurf;
 
 static void VblHandler() {
 	// for easier querying
-	static Graphics::Surface *surf;
+	static AtariSurface *surf;
 
 	if (s_screenSurf)
 		surf = s_screenSurf;
@@ -172,17 +168,22 @@ static Palette s_oldPalette;
 void AtariGraphicsShutdown() {
 	Supexec(UninstallVblHandler);
 
+	AtariSurfaceDeinit();
+
+#ifdef SCREEN_ACTIVE
 	if (s_oldRez != -1) {
 		Setscreen(SCR_NOCHANGE, s_oldPhysbase, s_oldRez);
 
 		EsetPalette(0, s_oldPalette.entries, s_oldPalette.tt);
+
+		s_oldRez = -1;
 	} else if (s_oldMode != -1) {
 		static _RGB black[256];
 		VsetRGB(0, 256, black);
 
 		VsetScreen(SCR_NOCHANGE, s_oldPhysbase, SCR_NOCHANGE, SCR_NOCHANGE);
 
-		if (hasSuperVidel()) {
+		if (g_hasSuperVidel) {
 			// SuperVidel XBIOS does not restore those (unlike TOS/EmuTOS)
 			long ssp = Super(SUP_SET);
 			//*((volatile char *)0xFFFF8265) = 0;
@@ -194,7 +195,10 @@ void AtariGraphicsShutdown() {
 		VsetMode(s_oldMode);
 
 		VsetRGB(0, s_oldPalette.entries, s_oldPalette.falcon);
+
+		s_oldMode = -1;
 	}
+#endif
 }
 
 AtariGraphicsManager::AtariGraphicsManager()
@@ -291,6 +295,14 @@ AtariGraphicsManager::AtariGraphicsManager()
 	}
 	s_oldPhysbase = Physbase();
 
+	AtariSurfaceInit();
+
+	allocateSurfaces();
+
+	if (!Supexec(InstallVblHandler)) {
+		error("VBL handler was not installed");
+	}
+
 	g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
 }
 
@@ -299,6 +311,12 @@ AtariGraphicsManager::~AtariGraphicsManager() {
 
 	g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
 
+	// this must be done here, too otherwise freeSurfaces() could release a surface
+	// still accessed by the vbl handler
+	Supexec(UninstallVblHandler);
+
+	freeSurfaces();
+
 	AtariGraphicsShutdown();
 }
 
@@ -402,19 +420,6 @@ void AtariGraphicsManager::beginGFXTransaction() {
 OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
 	atari_debug("endGFXTransaction");
 
-	{
-		// this can't be done in the c-tor because if the c-tor called error(),
-		// its d-tor wouldn't be called => the vbl handler wouldn't be uninstalled
-		// (for the same reason we don't do any resolution changes in the c-tor)
-		static bool vblHandlerInstalled;
-		if (!vblHandlerInstalled) {
-			if (!Supexec(InstallVblHandler)) {
-				error("VBL handler was not installed");
-			}
-			vblHandlerInstalled = true;
-		}
-	}
-
 	_pendingState.inTransaction = false;
 	_ignoreCursorChanges = false;
 
@@ -436,7 +441,7 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
 		} else if (((hasPendingGraphicsMode && _pendingState.mode == kDirectRendering)
 				|| (!hasPendingGraphicsMode && _currentState.mode == kDirectRendering))
 			&& _pendingState.width % 16 != 0
-			&& !hasSuperVidel()) {
+			&& !g_hasSuperVidel) {
 			atari_warning("Engine surfaces not divisible by 16, aborting");
 			error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
 		} else if (_overlayState == kOverlayIgnoredHide || _currentState.width != _pendingState.width || _currentState.height != _pendingState.height) {
@@ -467,7 +472,7 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
 	if ((hasPendingGraphicsMode || hasPendingSize) && _currentState.isValid()) {
 		int c2pWidth = _currentState.width;
 
-		if (!hasSuperVidel()) {
+		if (!g_hasSuperVidel) {
 			// make sure that c2p width is always divisible by 16
 			c2pWidth = (c2pWidth + 15) & -16;
 		}
@@ -480,26 +485,23 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
 		_chunkySurfaceOffsetted.init(_currentState.width, _currentState.height, c2pWidth,
 			_chunkySurface.getBasePtr(xOffset, 0), _currentState.format);
 
-		Common::Point oldCursorPosition = _screen[kFrontBuffer]->cursor.getPosition();
-
-		_screen[kFrontBuffer]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
+		_screen[kFrontBuffer]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
 		if (_currentState.mode > kSingleBuffering) {
-			_screen[kBackBuffer1]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
-			_screen[kBackBuffer2]->reset(c2pWidth, _currentState.height, 8, _chunkySurfaceOffsetted, xOffset, true);
+			_screen[kBackBuffer1]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
+			_screen[kBackBuffer2]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
 		}
 
 		{
-			Common::Event event;
+			Common::Event event = {};
 			event.type = Common::EVENT_MOUSEMOVE;
 			event.mouse = _screen[kFrontBuffer]->cursor.getPosition();
-			event.relMouse = event.mouse - oldCursorPosition;
 			g_system->getEventManager()->pushEvent(event);
 		}
 
 		if (hasPendingSize)
 			_pendingScreenChanges.queueVideoMode();
 
-		_pendingScreenChanges.setScreenSurface(&_screen[kFrontBuffer]->surf);
+		_pendingScreenChanges.setScreenSurface(_screen[kFrontBuffer]->surf.get());
 
 		_palette.clear();
 		// TODO: maybe we could update real start/num values
@@ -582,18 +584,20 @@ void AtariGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, i
 		x, y, w, h,
 		directRendering);
 
-	copyRectToScreenInternal(
-		dstSurface,
-		buf, pitch, x, y, w, h,
-		_currentState.format,
-		directRendering);
+	if (directRendering && !g_hasSuperVidel) {
+		copyRectToScreenInternal(
+			*_screen[kFrontBuffer]->offsettedSurf,
+			(const byte *)buf, pitch, x, y, w, h);
+	} else {
+		dstSurface.copyRectToSurface(buf, pitch, x, y, w, h);
+	}
 }
 
 Graphics::Surface *AtariGraphicsManager::lockScreen() {
 	//atari_debug("lockScreen");
 
 	return _currentState.mode == kDirectRendering
-		? _screen[kFrontBuffer]->offsettedSurf
+		? _screen[kFrontBuffer]->offsettedSurf->surfacePtr()
 		: &_chunkySurfaceOffsetted;
 }
 
@@ -666,7 +670,7 @@ void AtariGraphicsManager::updateScreen() {
 
 	assert(workScreen);
 
-	bool screenUpdated = updateScreenInternal(workScreen, srcSurface ? *srcSurface : Graphics::Surface());
+	bool screenUpdated = updateScreenInternal(workScreen, srcSurface);
 
 #ifdef SCREEN_ACTIVE
 	// this assume that the screen surface is not going to be used yet
@@ -697,7 +701,7 @@ void AtariGraphicsManager::updateScreen() {
 		_screen[kBackBuffer2] = tmp;
 
 		// queue BACK_BUFFER2 with the most recent frame content
-		_pendingScreenChanges.setScreenSurface(&_screen[kBackBuffer2]->surf);
+		_pendingScreenChanges.setScreenSurface(_screen[kBackBuffer2]->surf.get());
 		// BACK_BUFFER1 is now current (work) buffer
 	}
 
@@ -750,12 +754,11 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
 		_screen[kFrontBuffer]->cursor.flushBackground(Common::Rect(), true);
 	}
 
-	_pendingScreenChanges.setScreenSurface(&_screen[kOverlayBuffer]->surf);
+	_pendingScreenChanges.setScreenSurface(_screen[kOverlayBuffer]->surf.get());
 
 	// do not cache dirtyRects and saved cursor rect
 	_screen[kOverlayBuffer]->reset(
 		getOverlayWidth(), getOverlayHeight(),
-		getBitsPerPixel(getOverlayFormat()),
 		*lockOverlay(), 0,
 		false);
 
@@ -784,7 +787,7 @@ void AtariGraphicsManager::hideOverlay() {
 	// BACK_BUFFER2 is intentional: regardless of the state before calling showOverlay(),
 	// this always contains the next desired frame buffer to show
 	_pendingScreenChanges.setScreenSurface(
-		&_screen[_currentState.mode == kTripleBuffering ? kBackBuffer2 : kFrontBuffer]->surf);
+		_screen[_currentState.mode == kTripleBuffering ? kBackBuffer2 : kFrontBuffer]->surf.get());
 
 	_overlayState = kOverlayHidden;
 
@@ -894,10 +897,7 @@ void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
 		assert(surface.h >= _overlaySurface.h);
 		assert(surface.format.bytesPerPixel == _overlaySurface.format.bytesPerPixel);
 
-		const byte *src = (const byte *)_overlaySurface.getPixels();
-		byte *dst = (byte *)surface.getPixels();
-		Graphics::copyBlit(dst, src, surface.pitch,
-			_overlaySurface.pitch, _overlaySurface.w, _overlaySurface.h, _overlaySurface.format.bytesPerPixel);
+		surface.copyRectToSurface(_overlaySurface, 0, 0, Common::Rect(_overlaySurface.w, _overlaySurface.h));
 	}
 }
 
@@ -906,6 +906,7 @@ void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x,
 
 	Graphics::Surface &dstSurface = *lockOverlay();
 
+	// if true, SuperVidel is not present
 	const bool directRendering = isOverlayDirectRendering();
 
 	_screen[kOverlayBuffer]->addDirtyRect(
@@ -913,19 +914,21 @@ void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x,
 		x, y, w, h,
 		directRendering);
 
-	copyRectToScreenInternal(
-		dstSurface,
-		buf, pitch, x, y, w, h,
-		getOverlayFormat(),
-		directRendering);
+	if (directRendering) {
+		copyRectToScreenInternal(
+			*_screen[kOverlayBuffer]->offsettedSurf,
+			(const byte *)buf, pitch, x, y, w, h);
+	} else {
+		dstSurface.copyRectToSurface(buf, pitch, x, y, w, h);
+	}
 }
 
 Graphics::Surface *AtariGraphicsManager::lockOverlay() {
 	//atari_debug("lockOverlay");
 
 	return isOverlayDirectRendering()
-	   ? _screen[kOverlayBuffer]->offsettedSurf
-	   : &_overlaySurface;
+		? _screen[kOverlayBuffer]->offsettedSurf->surfacePtr()
+		: &_overlaySurface;
 }
 
 bool AtariGraphicsManager::showMouse(bool visible) {
@@ -1073,6 +1076,8 @@ void AtariGraphicsManager::allocateSurfaces() {
 		_screen[i] = new Screen(this, getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8, &_palette);
 	}
 	_screen[kOverlayBuffer] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
+	// initial position
+	_screen[kOverlayBuffer]->cursor.setPosition(getOverlayWidth() / 2, getOverlayHeight() / 2);
 
 	_chunkySurface.create(getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8);
 	_chunkySurfaceOffsetted = _chunkySurface;
@@ -1099,23 +1104,21 @@ void AtariGraphicsManager::addDirtyRectToScreens(const Graphics::Surface &dstSur
 	}
 }
 
-bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphics::Surface &srcSurface) {
+bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphics::Surface *srcSurface) {
 	//atari_debug("updateScreenInternal");
 
 	const Screen::DirtyRects &dirtyRects = dstScreen->dirtyRects;
-	Graphics::Surface *dstSurface        = dstScreen->offsettedSurf;
+	auto &dstSurface                     = *dstScreen->offsettedSurf;
 	Cursor &cursor                       = dstScreen->cursor;
 
-	const bool directRendering           = srcSurface.getPixels() == nullptr;
-
 	bool updated = false;
 
-	lockSuperBlitter();
+	LockSuperBlitter();
 
 	if (cursor.isChanged()) {
-		const Common::Rect cursorBackgroundRect = cursor.flushBackground(Common::Rect(), directRendering);
+		const Common::Rect cursorBackgroundRect = cursor.flushBackground(Common::Rect(), srcSurface == nullptr);
 		if (!cursorBackgroundRect.isEmpty()) {
-			copyRectToSurface(*dstSurface, srcSurface, cursorBackgroundRect.left, cursorBackgroundRect.top, cursorBackgroundRect);
+			dstSurface.copyRectToSurface(*srcSurface, cursorBackgroundRect.left, cursorBackgroundRect.top, cursorBackgroundRect);
 			updated |= true;
 		}
 	}
@@ -1125,9 +1128,9 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 
 	const bool drawCursor = cursor.isVisible() && (dstScreen->fullRedraw || cursor.isChanged());
 
-	if (!directRendering) {
+	if (srcSurface) {
 		for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
-			copyRectToSurface(*dstSurface, srcSurface, it->left, it->top, *it);
+			dstSurface.copyRectToSurface(*srcSurface, it->left, it->top, *it);
 		}
 		updated |= !dirtyRects.empty();
 	} else if (drawCursor) {
@@ -1135,7 +1138,7 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 	}
 
 	// unlock here because cursor.draw() is a software blit
-	unlockSuperBlitter();
+	UnlockSuperBlitter();
 
 	if (drawCursor) {
 		cursor.draw();
@@ -1147,23 +1150,12 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 	return updated;
 }
 
-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) {
-	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);
-		srcBuf -= (x - rect.left);	// HACK: this assumes pointer to a complete buffer
-		srcSurface.init(rect.width(), rect.height(), pitch, srcBuf, format);
-
-		copyRectToSurface(
-			dstSurface, srcSurface,
-			rect.left, rect.top,
-			Common::Rect(rect.width(), rect.height()));
-	} else {
-		dstSurface.copyRectToSurface(buf, pitch, x, y, w, h);
-	}
+void AtariGraphicsManager::copyRectToScreenInternal(AtariSurface &dstSurface,
+													const byte *buf, int pitch, int x, int y, int w, int h) {
+	const Common::Rect rect = alignRect(x, y, x + w, y + h);
+
+	// TODO: mask the unaligned parts and copy the rest
+	buf -= (x - rect.left);	// HACK: this assumes pointer to a complete buffer
+
+	dstSurface.copyRectToSurface(buf, pitch, rect.left, rect.top, rect.width(), rect.height());
 }
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 96ed4f0d06c..449bbfe5c89 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -25,20 +25,17 @@
 #include "backends/graphics/graphics.h"
 #include "common/events.h"
 
-#include <mint/osbind.h>
-
-#include "common/rect.h"
 #include "graphics/surface.h"
 
 #include "atari-cursor.h"
-#include "atari-graphics-superblitter.h"
 #include "atari-pendingscreenchanges.h"
 #include "atari-screen.h"
+#include "atari-supervidel.h"
 
 #define MAX_HZ_SHAKE 16 // Falcon only
 #define MAX_V_SHAKE  16
 
-class AtariGraphicsManager : public GraphicsManager, Common::EventObserver {
+class AtariGraphicsManager final : public GraphicsManager, Common::EventObserver {
 	friend class Cursor;
 	friend class PendingScreenChanges;
 	friend class Screen;
@@ -114,14 +111,6 @@ public:
 	bool notifyEvent(const Common::Event &event) override;
 	Common::Keymap *getKeymap() const;
 
-protected:
-	typedef void* (*AtariMemAlloc)(size_t bytes);
-	typedef void (*AtariMemFree)(void *ptr);
-
-	int getBitsPerPixel(const Graphics::PixelFormat &format) const;
-	void allocateSurfaces();
-	void freeSurfaces();
-
 private:
 	enum {
 		kUnknownMode		= -1,
@@ -134,6 +123,10 @@ private:
 		kActionToggleAspectRatioCorrection = 100,
 	};
 
+	int getBitsPerPixel(const Graphics::PixelFormat &format) const;
+	void allocateSurfaces();
+	void freeSurfaces();
+
 #ifndef DISABLE_FANCY_THEMES
 	int16 getMaximumScreenHeight() const { return 480; }
 	int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 640 : 640*1.2); }
@@ -144,18 +137,18 @@ private:
 
 	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);
+	bool updateScreenInternal(Screen *dstScreen, const Graphics::Surface *srcSurface);
+	void copyRectToScreenInternal(AtariSurface &dstSurface,
+								  const byte *buf, int pitch, int x, int y, int w, int h);
 
 	bool isOverlayDirectRendering() const {
+#ifndef DISABLE_FANCY_THEMES
 		// see osystem_atari.cpp
 		extern bool g_gameEngineActive;
-
+#endif
 		// 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()
+		// (on SuperVidel we always want to use _overlaySurface as source for background pixels)
+		return !g_hasSuperVidel
 #ifndef DISABLE_FANCY_THEMES
 			&& (!g_gameEngineActive || _currentState.mode == kDirectRendering)
 #endif
@@ -166,35 +159,17 @@ private:
 
 	Common::Rect alignRect(int x1, int y1, int x2, int y2) const {
 		// make non-virtual for performance reasons
-		return hasSuperVidel()
+		return g_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()
+		return g_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); };
-	}
-	virtual AtariMemFree getStRamFreeFunc() const {
-		return [](void *ptr) { Mfree(ptr); };
-	}
-
-	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,
-								  const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
-								  int destX, int destY,
-								  const Common::Rect &subRect) const = 0;
-
 	bool _vgaMonitor = true;
 	bool _tt = false;
 
diff --git a/backends/graphics/atari/atari-pendingscreenchanges.cpp b/backends/graphics/atari/atari-pendingscreenchanges.cpp
index 732b4bece39..b4c3c1ad7c9 100644
--- a/backends/graphics/atari/atari-pendingscreenchanges.cpp
+++ b/backends/graphics/atari/atari-pendingscreenchanges.cpp
@@ -28,7 +28,7 @@
 #include "graphics/surface.h"
 
 #include "atari-graphics.h"
-#include "atari-graphics-superblitter.h"
+#include "atari-supervidel.h"
 
 void PendingScreenChanges::queueAll() {
 	_changes |= kAll;
@@ -107,7 +107,7 @@ void PendingScreenChanges::processAspectRatioCorrection(const Screen &screen) {
 			_changes |= kVideoMode;
 		} else {
 			_aspectRatioCorrectionYOffset =
-				std::make_pair((screen.surf.h - 2*MAX_V_SHAKE - screen.offsettedSurf->h) / 2, true);
+				std::make_pair((screen.surf->h - 2*MAX_V_SHAKE - screen.offsettedSurf->h) / 2, true);
 			_shrinkVidelVisibleArea = std::make_pair(true, true);
 		}
 	} else {
@@ -121,7 +121,7 @@ void PendingScreenChanges::processAspectRatioCorrection(const Screen &screen) {
 			_aspectRatioCorrectionYOffset = std::make_pair(0, true);
 			_shrinkVidelVisibleArea = std::make_pair(false, true);
 
-			if (hasSuperVidel())
+			if (g_hasSuperVidel)
 				_resetSuperVidel = true;
 
 			// kPendingVideoMode will reset the shrunken Videl area
diff --git a/backends/graphics/atari/atari-pendingscreenchanges.h b/backends/graphics/atari/atari-pendingscreenchanges.h
index b1915432999..1342c877af2 100644
--- a/backends/graphics/atari/atari-pendingscreenchanges.h
+++ b/backends/graphics/atari/atari-pendingscreenchanges.h
@@ -25,10 +25,8 @@
 #include <utility>
 
 class AtariGraphicsManager;
+class AtariSurface;
 class Screen;
-namespace Graphics {
-class Surface;
-}
 
 class PendingScreenChanges {
 public:
@@ -40,7 +38,7 @@ public:
 		_changes &= ~kTransaction;
 	}
 
-	void setScreenSurface(Graphics::Surface *surface) {
+	void setScreenSurface(AtariSurface *surface) {
 		_surface = surface;
 	}
 
@@ -65,7 +63,7 @@ public:
 		return _changes == kNone;
 	}
 
-	Graphics::Surface *screenSurface() const {
+	AtariSurface *screenSurface() const {
 		return _surface;
 	}
 	const std::pair<int, bool>& aspectRatioCorrectionYOffset() const {
@@ -98,7 +96,7 @@ private:
 
 	const AtariGraphicsManager *_manager;
 
-	Graphics::Surface *_surface = nullptr;
+	AtariSurface *_surface = nullptr;
 
 	int _mode;
 	bool _resetSuperVidel;
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index dd591a2965d..06801215386 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -24,48 +24,43 @@
 #include <mint/falcon.h>
 
 #include "atari-graphics.h"
-#include "atari-graphics-superblitter.h"
+#include "atari-supervidel.h"
+#include "atari-surface.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, width / 2, height / 2)
+	, cursor(manager, this)
 	, palette(palette_) {
-	const AtariGraphicsManager::AtariMemAlloc &allocFunc = _manager->getStRamAllocFunc();
-
-	surf.init(
-		width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE),
-		height + 2 * MAX_V_SHAKE,
-		(width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE)) * _manager->getBitsPerPixel(format) / 8,
-		nullptr,
-		format);
-
-	void *pixelsUnaligned = allocFunc(sizeof(uintptr) + (surf.h * surf.pitch) + ALIGN - 1);
-	if (!pixelsUnaligned) {
-		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
-	*((uintptr *)surf.getPixels() - 1) = (uintptr)pixelsUnaligned;
-
-	memset(surf.getPixels(), 0, surf.h * surf.pitch);
 
-	_offsettedSurf.init(
-		width, height, surf.pitch,
-		surf.getBasePtr((surf.w - width) / 2, (surf.h - height) / 2),
-		surf.format);
-}
+	const int bitsPerPixel = _manager->getBitsPerPixel(format);
 
-Screen::~Screen() {
-	const AtariGraphicsManager::AtariMemFree &freeFunc = _manager->getStRamFreeFunc();
+	if (g_hasSuperVidel) {
+		surf.reset(new SuperVidelSurface(
+			width + 2 * MAX_HZ_SHAKE,
+			height + 2 * MAX_V_SHAKE,
+			format,
+			bitsPerPixel));
+		_offsettedSurf.reset(new SuperVidelSurface(bitsPerPixel));
+	} else {
+		surf.reset(new AtariSurface(
+			width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE),
+			height + 2 * MAX_V_SHAKE,
+			format,
+			bitsPerPixel));
+		_offsettedSurf.reset(new AtariSurface(bitsPerPixel));
+	}
 
-	freeFunc((void *)*((uintptr *)surf.getPixels() - 1));
+	_offsettedSurf->create(
+		*surf,
+		Common::Rect(
+			Common::Point(
+				(surf->w - width) / 2,		// left
+				(surf->h - height) / 2),	// top
+			width, height));
 }
 
-void Screen::reset(int width, int height, int bitsPerPixel, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition) {
+void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition) {
 	_xOffset = xOffset;
 
 	clearDirtyRects();
@@ -75,67 +70,72 @@ void Screen::reset(int width, int height, int bitsPerPixel, const Graphics::Surf
 	rez = -1;
 	mode = -1;
 
+	const int bitsPerPixel = _manager->getBitsPerPixel(surf->format);
+
 	// erase old screen
-	_offsettedSurf.fillRect(Common::Rect(_offsettedSurf.w, _offsettedSurf.h), 0);
+	_offsettedSurf->fillRect(_offsettedSurf->getBounds(), 0);
 
 	if (_manager->_tt) {
 		if (width <= 320 && height <= 240) {
-			surf.w = 320;
-			surf.h = 240 + 2 * MAX_V_SHAKE;
-			surf.pitch = 2 * surf.w * bitsPerPixel / 8;
+			surf->w = 320;
+			surf->h = 240 + 2 * MAX_V_SHAKE;
+			surf->pitch = 2 * surf->w * bitsPerPixel / 8;
 			rez = kRezValueTTLow;
 		} else {
-			surf.w = 640;
-			surf.h = 480 + 2 * MAX_V_SHAKE;
-			surf.pitch = surf.w * bitsPerPixel / 8;
+			surf->w = 640;
+			surf->h = 480 + 2 * MAX_V_SHAKE;
+			surf->pitch = surf->w * bitsPerPixel / 8;
 			rez = kRezValueTTMid;
 		}
 	} else {
 		mode = VsetMode(VM_INQUIRE) & PAL;
 
 		if (_manager->_vgaMonitor) {
-			mode |= VGA | (bitsPerPixel == 4 ? BPS4 : (hasSuperVidel() ? BPS8C : BPS8));
+			mode |= VGA | (bitsPerPixel == 4 ? BPS4 : (g_hasSuperVidel ? BPS8C : BPS8));
 
 			if (width <= 320 && height <= 240) {
-				surf.w = 320;
-				surf.h = 240;
+				surf->w = 320;
+				surf->h = 240;
 				mode |= VERTFLAG | COL40;
 			} else {
-				surf.w = 640;
-				surf.h = 480;
+				surf->w = 640;
+				surf->h = 480;
 				mode |= COL80;
 			}
 		} else {
 			mode |= TV | (bitsPerPixel == 4 ? BPS4 : BPS8);
 
 			if (width <= 320 && height <= 200) {
-				surf.w = 320;
-				surf.h = 200;
+				surf->w = 320;
+				surf->h = 200;
 				mode |= COL40;
 			} else if (width <= 320*1.2 && height <= 200*1.2) {
-				surf.w = 320*1.2;
-				surf.h = 200*1.2;
+				surf->w = 320*1.2;
+				surf->h = 200*1.2;
 				mode |= OVERSCAN | COL40;
 			} else if (width <= 640 && height <= 400) {
-				surf.w = 640;
-				surf.h = 400;
+				surf->w = 640;
+				surf->h = 400;
 				mode |= VERTFLAG | COL80;
 			} else {
-				surf.w = 640*1.2;
-				surf.h = 400*1.2;
+				surf->w = 640*1.2;
+				surf->h = 400*1.2;
 				mode |= VERTFLAG | OVERSCAN | COL80;
 			}
 		}
 
-		surf.w += 2 * MAX_HZ_SHAKE;
-		surf.h += 2 * MAX_V_SHAKE;
-		surf.pitch = surf.w * bitsPerPixel / 8;
+		surf->w += 2 * MAX_HZ_SHAKE;
+		surf->h += 2 * MAX_V_SHAKE;
+		surf->pitch = surf->w * bitsPerPixel / 8;
 	}
 
-	_offsettedSurf.init(
-		width, height, surf.pitch,
-		surf.getBasePtr((surf.w - width) / 2, (surf.h - height) / 2),
-		surf.format);
+	_offsettedSurf->create(
+		*surf,
+		Common::Rect(
+			Common::Point(
+				(surf->w - width) / 2,		// left
+				(surf->h - height) / 2),	// top
+			width, height));
 }
 
 void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering) {
diff --git a/backends/graphics/atari/atari-screen.h b/backends/graphics/atari/atari-screen.h
index 2cd49e0d8aa..ce7812e433a 100644
--- a/backends/graphics/atari/atari-screen.h
+++ b/backends/graphics/atari/atari-screen.h
@@ -23,12 +23,12 @@
 #define BACKENDS_GRAPHICS_ATARI_SCREEN_H
 
 #include <unordered_set>
-#include <mint/ostruct.h>
+#include <mint/ostruct.h>	// _RGB
 
-#include "common/rect.h"
-#include "graphics/surface.h"
+#include "common/ptr.h"
 
 #include "atari-cursor.h"
+#include "atari-surface.h"
 
 template<>
 struct std::hash<Common::Rect>
@@ -44,26 +44,25 @@ class AtariGraphicsManager;
 class Palette {
 public:
 	void clear() {
-		memset(data, 0, sizeof(data));
+		memset(_data, 0, sizeof(_data));
 		entries = 0;
 	}
 
-	uint16 *const tt = reinterpret_cast<uint16*>(data);
-	_RGB *const falcon = reinterpret_cast<_RGB*>(data);
+	uint16 *const tt = reinterpret_cast<uint16*>(_data);
+	_RGB *const falcon = reinterpret_cast<_RGB*>(_data);
 
 	int entries = 0;
 
 private:
-	byte data[256*4] = {};
+	byte _data[256*4] = {};
 };
 
 struct Screen {
 	using DirtyRects = std::unordered_set<Common::Rect>;
 
 	Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
-	~Screen();
 
-	void reset(int width, int height, int bitsPerPixel, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition);
+	void reset(int width, int height, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition);
 	// must be called before any rectangle drawing
 	void addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering);
 
@@ -72,7 +71,7 @@ struct Screen {
 		fullRedraw = false;
 	}
 
-	Graphics::Surface surf;
+	Common::ScopedPtr<AtariSurface> surf;
 	const Palette *palette;
 	DirtyRects dirtyRects;
 	bool fullRedraw = false;
@@ -81,7 +80,7 @@ struct Screen {
 
 	int rez = -1;
 	int mode = -1;
-	Graphics::Surface *const offsettedSurf = &_offsettedSurf;
+	const Common::ScopedPtr<AtariSurface> &offsettedSurf = _offsettedSurf;
 
 private:
 	static constexpr size_t ALIGN = 16;	// 16 bytes
@@ -97,7 +96,7 @@ private:
 
 	const AtariGraphicsManager *_manager;
 
-	Graphics::Surface _offsettedSurf;
+	Common::ScopedPtr<AtariSurface> _offsettedSurf;
 	int _xOffset = 0;
 };
 
diff --git a/backends/graphics/atari/atari-graphics-superblitter.h b/backends/graphics/atari/atari-supervidel.cpp
similarity index 55%
rename from backends/graphics/atari/atari-graphics-superblitter.h
rename to backends/graphics/atari/atari-supervidel.cpp
index 32be0380750..d9bfef5ac98 100644
--- a/backends/graphics/atari/atari-graphics-superblitter.h
+++ b/backends/graphics/atari/atari-supervidel.cpp
@@ -19,36 +19,48 @@
  *
  */
 
-#ifndef BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
-#define BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
+#include "atari-supervidel.h"
 
-#ifdef USE_SUPERVIDEL
+#include "common/scummsys.h"
 
-#include <mint/cookie.h>
-#include <mint/falcon.h>
+bool g_hasSuperVidel = false;
 
-// bits 9:0
-#define SV_VERSION	((volatile long *)0x8001007C)
+#ifdef USE_SUPERVIDEL
 
-inline static bool hasSuperVidel() {
-	// this works also on the TT
-	static bool hasSuperVidel = Getcookie(C_SupV, NULL) == C_FOUND && VgetMonitor() == MON_VGA;
-	return hasSuperVidel;
-}
+#ifdef USE_SV_BLITTER
+int g_superVidelFwVersion = 0;
 
-static int superVidelFwVersion = hasSuperVidel() ? *SV_VERSION & 0x01ff : 0;
+static bool isSuperBlitterLocked;
 
-#else
+void SyncSuperBlitter() {
+	// if externally locked, let the owner decide when to sync (unlock)
+	if (isSuperBlitterLocked)
+		return;
 
-constexpr bool hasSuperVidel() {
-	return false;
+	// while FIFO not empty...
+	if (g_superVidelFwVersion >= 9)
+		while (!(*SV_BLITTER_FIFO & 1));
+	// while busy blitting...
+	while (*SV_BLITTER_CONTROL & 1);
 }
+#endif	// USE_SV_BLITTER
 
-constexpr int superVidelFwVersion = 0;
+void LockSuperBlitter() {
+#ifdef USE_SV_BLITTER
+	assert(!isSuperBlitterLocked);
 
-#endif	// USE_SUPERVIDEL
+	isSuperBlitterLocked = true;
+#endif
+}
 
-void lockSuperBlitter();
-void unlockSuperBlitter();
+void UnlockSuperBlitter() {
+#ifdef USE_SV_BLITTER
+	assert(isSuperBlitterLocked);
 
+	isSuperBlitterLocked = false;
+	if (g_hasSuperVidel)
+		SyncSuperBlitter();
 #endif
+}
+
+#endif	// USE_SUPERVIDEL
diff --git a/backends/graphics/atari/atari-supervidel.h b/backends/graphics/atari/atari-supervidel.h
new file mode 100644
index 00000000000..c2725c4d718
--- /dev/null
+++ b/backends/graphics/atari/atari-supervidel.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
+#define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
+
+#ifdef USE_SUPERVIDEL
+
+// bits 26:0
+#define SV_BLITTER_SRC1           ((volatile long *)0x80010058)
+#define SV_BLITTER_SRC2           ((volatile long *)0x8001005C)
+#define SV_BLITTER_DST            ((volatile long *)0x80010060)
+// The amount of bytes that are to be copied in a horizontal line, minus 1
+#define SV_BLITTER_COUNT          ((volatile long *)0x80010064)
+// The amount of bytes that are to be added to the line start address after a line has been copied, in order to reach the next one
+#define SV_BLITTER_SRC1_OFFSET    ((volatile long *)0x80010068)
+#define SV_BLITTER_SRC2_OFFSET    ((volatile long *)0x8001006C)
+#define SV_BLITTER_DST_OFFSET     ((volatile long *)0x80010070)
+// bits 11:0 - The amount of horizontal lines to do
+#define SV_BLITTER_MASK_AND_LINES ((volatile long *)0x80010074)
+// bit    0 - busy / start
+// bits 4:1 - blit mode
+#define SV_BLITTER_CONTROL        ((volatile long *)0x80010078)
+// bits 9:0
+#define SV_VERSION                ((volatile long *)0x8001007C)
+// bit 0 - empty (read only)
+// bit 1 - full (read only)
+// bits 31:0 - data (write only)
+#define SV_BLITTER_FIFO           ((volatile long *)0x80010080)
+
+#ifdef USE_SV_BLITTER
+extern int g_superVidelFwVersion;
+
+void SyncSuperBlitter();
+#endif	// USE_SV_BLITTER
+
+void LockSuperBlitter();
+void UnlockSuperBlitter();
+
+#else
+
+static inline void LockSuperBlitter() {}
+static inline void UnlockSuperBlitter() {}
+
+#endif	// USE_SUPERVIDEL
+
+extern bool g_hasSuperVidel;
+
+#endif // BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
diff --git a/backends/graphics/atari/atari-surface.cpp b/backends/graphics/atari/atari-surface.cpp
new file mode 100644
index 00000000000..efa9dcc9c0e
--- /dev/null
+++ b/backends/graphics/atari/atari-surface.cpp
@@ -0,0 +1,365 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "atari-surface.h"
+#include "graphics/surface.h"
+
+#include <mint/cookie.h>
+#include <mint/falcon.h>
+#include <mint/trap14.h>
+#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
+#define ct60_vmalloc(value)  ct60_vm(0, value)
+#define ct60_vmfree(value)   ct60_vm(1, value)
+
+#include "backends/graphics/atari/atari-c2p-asm.h"
+#include "backends/graphics/atari/atari-graphics-asm.h"
+#include "backends/graphics/atari/atari-supervidel.h"
+#include "backends/platform/atari/atari-debug.h"
+#include "backends/platform/atari/dlmalloc.h"
+#include "common/textconsole.h"	// error()
+
+static struct MemoryPool {
+	void create() {
+		if (base)
+			_mspace = create_mspace_with_base((void *)base, size, 0);
+
+		if (_mspace)
+			atari_debug("Allocated mspace at 0x%08lx (%ld bytes)", base, size);
+		else
+			error("mspace allocation failed at 0x%08lx (%ld bytes)", base, size);
+	}
+
+	void destroy() {
+		if (_mspace) {
+			destroy_mspace(_mspace);
+			_mspace = nullptr;
+		}
+	}
+
+	void *malloc(size_t bytes) {
+		assert(_mspace);
+		return mspace_malloc(_mspace, bytes);
+	}
+
+	void *calloc(size_t n_elements, size_t elem_size) {
+		assert(_mspace);
+		return mspace_calloc(_mspace, n_elements, elem_size);
+	}
+
+	void free(void *mem) {
+		assert(_mspace);
+		mspace_free(_mspace, mem);
+	}
+
+	long base;
+	long size;
+
+private:
+	mspace _mspace;
+} s_videoRamPool, s_blitterPool;
+
+static MemoryPool *s_currentPool;
+
+namespace Graphics {
+
+void Surface::create(int16 width, int16 height, const PixelFormat &f) {
+	assert(width >= 0 && height >= 0);
+	free();
+
+	w = width;
+	h = height;
+	format = f;
+	pitch = w * format.bytesPerPixel;
+
+	if (width && height) {
+		if (s_currentPool) {
+			pixels = s_currentPool->calloc(height * pitch, format.bytesPerPixel);
+			if (!pixels)
+				error("Not enough VRAM to allocate a surface");
+
+			if (s_currentPool == &s_blitterPool) {
+				assert(pixels >= (void *)0xA1000000);
+			} else if (s_currentPool == &s_videoRamPool) {
+#ifdef USE_SUPERVIDEL
+				if (g_hasSuperVidel)
+					assert(pixels >= (void *)0xA0000000 && pixels < (void *)0xA1000000);
+				else
+#endif
+					assert(pixels < (void *)0x01000000);
+			}
+		} else {
+			pixels = ::calloc(height * pitch, format.bytesPerPixel);
+			if (!pixels)
+				error("Not enough RAM to allocate a surface");
+		}
+
+		assert(((uintptr)pixels & (MALLOC_ALIGNMENT - 1)) == 0);
+	}
+}
+
+void Surface::free() {
+	if (pixels) {
+		if (s_currentPool)
+			s_currentPool->free(pixels);
+		else
+			::free(pixels);
+
+		pixels = nullptr;
+	}
+
+	w = h = pitch = 0;
+	format = PixelFormat();
+}
+
+} // End of namespace Graphics
+
+///////////////////////////////////////////////////////////////////////////////
+
+AtariSurface::AtariSurface(int bitsPerPixel)
+	: _bitsPerPixel(bitsPerPixel) {
+}
+
+AtariSurface::AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel)
+	: _bitsPerPixel(bitsPerPixel) {
+	create(width, height, pixelFormat);
+}
+
+AtariSurface::~AtariSurface() {
+	free();
+}
+
+void AtariSurface::create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) {
+	MemoryPool *oldPool = s_currentPool;
+	s_currentPool = &s_videoRamPool;
+
+	Graphics::ManagedSurface::create(width * _bitsPerPixel / 8, height, pixelFormat);
+	w = width;
+
+	s_currentPool = oldPool;
+}
+
+void AtariSurface::free() {
+	MemoryPool *oldPool = s_currentPool;
+	s_currentPool = &s_videoRamPool;
+
+	Graphics::ManagedSurface::free();
+
+	s_currentPool = oldPool;
+}
+
+void AtariSurface::copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
+	assert(width % 16 == 0);
+	assert(destX % 16 == 0);
+
+	// '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*
+	// 2. (subRect.right, subRect.bottom) = even worse, end of the *next* line, not current one
+	const byte *pChunky    = (const byte *)buffer;
+	const byte *pChunkyEnd = pChunky + (height - 1) * srcPitch + width * format.bytesPerPixel;
+
+	byte *pScreen = (byte *)getPixels() + destY * pitch + destX * _bitsPerPixel/8;
+
+	if (_bitsPerPixel == 8) {
+		if (srcPitch == width) {
+			if (srcPitch == pitch) {
+				asm_c2p1x1_8(pChunky, pChunkyEnd, pScreen);
+				return;
+			} else if (srcPitch == pitch/2) {
+				asm_c2p1x1_8_tt(pChunky, pChunkyEnd, pScreen, pitch);
+				return;
+			}
+		}
+
+		asm_c2p1x1_8_rect(
+			pChunky, pChunkyEnd,
+			width,
+			srcPitch,
+			pScreen,
+			pitch);
+	} else {
+		if (srcPitch == width && srcPitch/2 == pitch) {
+			asm_c2p1x1_4(pChunky, pChunkyEnd, pScreen);
+			return;
+		}
+
+		asm_c2p1x1_4_rect(
+			pChunky, pChunkyEnd,
+			width,
+			srcPitch,
+			pScreen,
+			pitch);
+	}
+}
+
+void AtariSurface::drawMaskedSprite(
+	const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+	int destX, int destY,
+	const Common::Rect &subRect) {
+	assert(subRect.width() % 16 == 0);
+	assert(subRect.width() == srcSurface.w);
+	assert(srcSurface.format == format);
+
+	if (_bitsPerPixel == 4) {
+		asm_draw_4bpl_sprite(
+			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
+			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
+			destX, destY,
+			pitch, subRect.width(), subRect.height());
+	} else if (_bitsPerPixel == 8) {
+		asm_draw_8bpl_sprite(
+			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
+			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
+			destX, destY,
+			pitch, subRect.width(), subRect.height());
+	}
+}
+
+void SuperVidelSurface::drawMaskedSprite(
+	const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+	int destX, int destY,
+	const Common::Rect &subRect) {
+	assert(subRect.width() % 16 == 0);
+	assert(subRect.width() == srcSurface.w);
+	assert(srcSurface.format == format);
+	assert(_bitsPerPixel == 8);
+
+	const byte *src = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
+	const uint16 *mask = (const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top);
+	byte *dst = (byte *)getBasePtr(destX, destY);
+
+	const int height = subRect.height();
+	const int width = subRect.width();
+	const int dstOffset = pitch - width;
+
+	for (int j = 0; j < height; ++j) {
+		for (int i = 0; i < width; i += 16, mask++) {
+			const uint16 m = *mask;
+
+			if (m == 0xFFFF) {
+				// all 16 pixels transparent
+				src += 16;
+				dst += 16;
+				continue;
+			}
+
+			for (int k = 0; k < 16; ++k) {
+				const uint16 bit = 1 << (15 - k);
+
+				if (m & bit) {
+					// transparent
+					src++;
+					dst++;
+				} else {
+					*dst++ = *src++;
+				}
+			}
+		}
+
+		dst += dstOffset;
+	}
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef USE_SUPERVIDEL
+static long hasSvRamBoosted() {
+	register long ret __asm__ ("d0") = 0;
+
+	__asm__ volatile(
+		"\tmovec	%%itt0,%%d1\n"
+		"\tcmp.l	#0xA007E060,%%d1\n"
+		"\tbne.s	1f\n"
+
+		"\tmovec	%%dtt0,%%d1\n"
+		"\tcmp.l	#0xA007E060,%%d1\n"
+		"\tbne.s	1f\n"
+
+		"\tmoveq	#1,%%d0\n"
+
+		"1:\n"
+		: "=g"(ret)	/* outputs */
+		:			/* inputs  */
+		: __CLOBBER_RETURN("d0") "d1", "cc"
+		);
+
+	return ret;
+}
+#endif	// USE_SUPERVIDEL
+
+void AtariSurfaceInit() {
+#ifdef USE_SUPERVIDEL
+	g_hasSuperVidel = Getcookie(C_SupV, NULL) == C_FOUND && VgetMonitor() == MON_VGA;
+
+	if (g_hasSuperVidel) {
+#ifdef USE_SV_BLITTER
+		g_superVidelFwVersion = *SV_VERSION & 0x01ff;
+
+		atari_debug("SuperVidel FW Revision: %d, using %s", g_superVidelFwVersion,
+			g_superVidelFwVersion >= 9 ? "fast async FIFO" : "slower sync blitting");
+#else
+		atari_debug("SuperVidel FW Revision: %d, SuperBlitter not used", *SV_VERSION & 0x01ff);
+#endif
+		if (Supexec(hasSvRamBoosted))
+			atari_debug("SV_XBIOS has the pmmu boost enabled");
+		else
+			atari_warning("SV_XBIOS has the pmmu boost disabled, set 'pmmu_boost = true' in C:\\SV.INF");
+
+#ifdef USE_SV_BLITTER
+		s_blitterPool.size = ct60_vmalloc(-1) - (16 * 1024 * 1024);	// SV XBIOS seems to forget the initial 16 MB ST RAM mirror
+		s_blitterPool.base = s_blitterPool.size > 0 ? ct60_vmalloc(s_blitterPool.size) : 0;
+		s_blitterPool.create();
+		// default pool is either null or blitter
+		s_currentPool = &s_blitterPool;
+#endif
+	}
+#endif	// USE_SUPERVIDEL
+
+	s_videoRamPool.size = 2 * 1024 * 1024;	// allocate 2 MiB, leave the rest for SDMA / Blitter usage
+	s_videoRamPool.base = s_videoRamPool.size > 0 ? Mxalloc(s_videoRamPool.size, MX_STRAM) : 0;
+#ifdef USE_SUPERVIDEL
+	if (g_hasSuperVidel && s_videoRamPool.base)
+		s_videoRamPool.base |= 0xA0000000;
+#endif
+	s_videoRamPool.create();
+}
+
+void AtariSurfaceDeinit() {
+	s_videoRamPool.destroy();
+	if (s_videoRamPool.base) {
+#ifdef USE_SUPERVIDEL
+		if (g_hasSuperVidel)
+			s_videoRamPool.base &= 0x00FFFFFF;
+#endif
+		Mfree(s_videoRamPool.base);
+		s_videoRamPool.base = 0;
+		s_videoRamPool.size = 0;
+	}
+
+#ifdef USE_SV_BLITTER
+	s_blitterPool.destroy();
+	if (s_blitterPool.base) {
+		ct60_vmfree(s_blitterPool.base);
+		s_blitterPool.base = 0;
+		s_blitterPool.size = 0;
+	}
+#endif
+}
diff --git a/backends/graphics/atari/atari-surface.h b/backends/graphics/atari/atari-surface.h
new file mode 100644
index 00000000000..62bcca36883
--- /dev/null
+++ b/backends/graphics/atari/atari-surface.h
@@ -0,0 +1,84 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef BACKENDS_GRAPHICS_ATARI_SURFACE_H
+#define BACKENDS_GRAPHICS_ATARI_SURFACE_H
+
+#include "graphics/managed_surface.h"
+
+class AtariSurface : public Graphics::ManagedSurface {
+public:
+	AtariSurface(int bitsPerPixel);
+	AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel);
+	~AtariSurface() override;
+
+	using Graphics::ManagedSurface::create;
+	void create(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) final override;
+	void free() final override;
+
+	void addDirtyRect(const Common::Rect &r) final override {};
+
+	// no override as ManagedSurface::copyRectToSurface is not a virtual function!
+	virtual void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height);
+	virtual void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &subRect) {
+		assert(subRect.left % 16 == 0);
+		assert(srcSurface.format == format);
+
+		copyRectToSurface(
+			srcSurface.getBasePtr(subRect.left, subRect.top), srcSurface.pitch,
+			destX, destY,
+			subRect.width(), subRect.height());
+	}
+
+	virtual void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+								  int destX, int destY,
+								  const Common::Rect &subRect);
+
+protected:
+	int _bitsPerPixel = 0;
+};
+
+class SuperVidelSurface final : public AtariSurface {
+public:
+	SuperVidelSurface(int bitsPerPixel)
+		: AtariSurface(bitsPerPixel) {
+	}
+	SuperVidelSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel)
+		: AtariSurface(width, height, pixelFormat, bitsPerPixel) {
+	}
+
+	//using Graphics::ManagedSurface::copyRectToSurface;
+	void copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) override {
+		Graphics::ManagedSurface::copyRectToSurface(buffer, srcPitch, destX, destY, width, height);
+	}
+	void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &subRect) override {
+		Graphics::ManagedSurface::copyRectToSurface(srcSurface, destX, destY, subRect);
+	}
+
+	void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+						  int destX, int destY,
+						  const Common::Rect &subRect) override;
+};
+
+void AtariSurfaceInit();
+void AtariSurfaceDeinit();
+
+#endif // BACKENDS_GRAPHICS_ATARI_SURFACE_H
diff --git a/backends/module.mk b/backends/module.mk
index e73da595cbc..66c7ecc37d1 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -387,6 +387,8 @@ MODULE_OBJS += \
 	graphics/atari/atari-graphics-asm.o \
 	graphics/atari/atari-pendingscreenchanges.o \
 	graphics/atari/atari-screen.o \
+	graphics/atari/atari-supervidel.o \
+	graphics/atari/atari-surface.o \
 	mixer/atari/atari-mixer.o
 endif
 
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index 663a8a47cd4..464e66d2029 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -46,10 +46,6 @@
 #include "common/config-manager.h"
 #include "backends/events/atari/atari-events.h"
 #include "backends/events/default/default-events.h"
-#include "backends/graphics/atari/atari-graphics-asm.h"
-#include "backends/graphics/atari/atari-graphics-superblitter.h"
-#include "backends/graphics/atari/atari-graphics-supervidel.h"
-#include "backends/graphics/atari/atari-graphics-videl.h"
 #include "backends/graphics/atari/atari-graphics.h"
 #include "backends/keymapper/hardware-input.h"
 #include "backends/mixer/atari/atari-mixer.h"
@@ -78,10 +74,11 @@ extern void nf_init(void);
 extern void nf_print(const char* msg);
 
 static int s_app_id = -1;
+static void (*s_old_procterm)(void) = nullptr;
 
 static volatile uint32 counter_200hz;
 
-static bool exit_already_called = false;
+static bool s_dtor_already_called = false;
 
 static long atari_200hz_init(void)
 {
@@ -129,11 +126,7 @@ static long atari_200hz_shutdown(void)
 }
 
 static void critical_restore() {
-	extern void AtariAudioShutdown();
-	extern void AtariGraphicsShutdown();
-
-	AtariAudioShutdown();
-	AtariGraphicsShutdown();
+	//atari_debug("critical_restore()");
 
 	Supexec(atari_200hz_shutdown);
 
@@ -154,12 +147,25 @@ static void critical_restore() {
 		graf_mouse(M_ON, NULL);
 	}
 #endif
+
+	// avoid infinite recursion if either of the shutdown procedures fails
+	(void)Setexc(VEC_PROCTERM, s_old_procterm);
+
+	extern void AtariAudioShutdown();
+	extern void AtariGraphicsShutdown();
+
+	AtariAudioShutdown();
+	AtariGraphicsShutdown();
 }
 
 // called on normal program termination (via exit() or returning from main())
 static void exit_restore() {
-	if (!exit_already_called)
+	// causes a crash upon termination
+	//atari_debug("exit_restore()");
+
+	if (!s_dtor_already_called)
 		g_system->destroy();
+	// else critical_restore() will be called, too
 }
 
 OSystem_Atari::OSystem_Atari() {
@@ -218,13 +224,15 @@ OSystem_Atari::OSystem_Atari() {
 	// protect against sudden exit()
 	atexit(exit_restore);
 	// protect against sudden crash
-	_old_procterm = Setexc(VEC_PROCTERM, -1);
+	s_old_procterm = Setexc(VEC_PROCTERM, -1);
 	(void)Setexc(VEC_PROCTERM, critical_restore);
 }
 
 OSystem_Atari::~OSystem_Atari() {
 	atari_debug("OSystem_Atari::~OSystem_Atari()");
 
+	s_dtor_already_called = true;
+
 	// _audiocdManager needs to be deleted before _mixerManager to avoid a crash.
 	delete _audiocdManager;
 	_audiocdManager = nullptr;
@@ -271,11 +279,12 @@ OSystem_Atari::~OSystem_Atari() {
 	}
 
 	// graceful exit
-	exit_already_called = true;
-	(void)Setexc(VEC_PROCTERM, _old_procterm);
+	(void)Setexc(VEC_PROCTERM, s_old_procterm);
 }
 
 void OSystem_Atari::initBackend() {
+	atari_debug("OSystem_Atari::initBackend()");
+
 	s_app_id = appl_init();
 	if (s_app_id != -1) {
 		// get the ID of the current physical screen workstation
@@ -314,13 +323,7 @@ void OSystem_Atari::initBackend() {
 	_eventManager = new DefaultEventManager(makeKeyboardRepeatingEventSource(atariEventSource));
 
 	// AtariGraphicsManager needs _eventManager ready
-	AtariGraphicsManager *atariGraphicsManager;
-#ifdef USE_SUPERVIDEL
-	if (hasSuperVidel())
-		atariGraphicsManager = new AtariSuperVidelManager();
-	else
-#endif
-		atariGraphicsManager = new AtariVidelManager();
+	AtariGraphicsManager *atariGraphicsManager = new AtariGraphicsManager();
 	_graphicsManager = atariGraphicsManager;
 
 	atariEventSource->setGraphicsManager(atariGraphicsManager);
@@ -410,7 +413,17 @@ Common::HardwareInputSet *OSystem_Atari::getHardwareInputSet() {
 void OSystem_Atari::quit() {
 	atari_debug("OSystem_Atari::quit()");
 
-	destroy();
+	if (!s_dtor_already_called)
+		destroy();
+}
+
+void OSystem_Atari::fatalError() {
+	atari_debug("OSystem_Atari::fatalError()");
+
+	quit();
+
+	// let exit_restore() and critical_restore() handle the recovery
+	exit(1);
 }
 
 void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
diff --git a/backends/platform/atari/osystem_atari.h b/backends/platform/atari/osystem_atari.h
index c3be4d8e1a6..b45f4413b7f 100644
--- a/backends/platform/atari/osystem_atari.h
+++ b/backends/platform/atari/osystem_atari.h
@@ -24,7 +24,7 @@
 
 #include "backends/modular-backend.h"
 
-class OSystem_Atari : public ModularMixerBackend, public ModularGraphicsBackend {
+class OSystem_Atari final : public ModularMixerBackend, public ModularGraphicsBackend {
 public:
 	OSystem_Atari();
 	virtual ~OSystem_Atari();
@@ -43,6 +43,7 @@ public:
 	Common::HardwareInputSet *getHardwareInputSet() override;
 
 	void quit() override;
+	void fatalError() override;
 
 	void logMessage(LogMessageType::Type type, const char *message) override;
 
@@ -59,8 +60,6 @@ private:
 	int16 _vdi_handle;
 	int _vdi_width;
 	int _vdi_height;
-
-	void (*_old_procterm)(void) = nullptr;
 };
 
 #endif
diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index e4d807a2e12..6e4540b537f 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -20,51 +20,13 @@
  */
 
 #include "graphics/blit.h"
-#include "graphics/surface.h"
-#include "backends/platform/atari/dlmalloc.h"
 
-#include <cstdlib>	// malloc
-#include <cstring>	// memcpy, memset
 #include <mint/cookie.h>
 
-#include "backends/graphics/atari/atari-graphics-superblitter.h"
-#include "common/textconsole.h"	// error
+#include "backends/graphics/atari/atari-supervidel.h"
+#include "backends/platform/atari/dlmalloc.h"	// MALLOC_ALIGNMENT
 
-// bits 26:0
-#define SV_BLITTER_SRC1           ((volatile long *)0x80010058)
-#define SV_BLITTER_SRC2           ((volatile long *)0x8001005C)
-#define SV_BLITTER_DST            ((volatile long *)0x80010060)
-// The amount of bytes that are to be copied in a horizontal line, minus 1
-#define SV_BLITTER_COUNT          ((volatile long *)0x80010064)
-// The amount of bytes that are to be added to the line start address after a line has been copied, in order to reach the next one
-#define SV_BLITTER_SRC1_OFFSET    ((volatile long *)0x80010068)
-#define SV_BLITTER_SRC2_OFFSET    ((volatile long *)0x8001006C)
-#define SV_BLITTER_DST_OFFSET     ((volatile long *)0x80010070)
-// bits 11:0 - The amount of horizontal lines to do
-#define SV_BLITTER_MASK_AND_LINES ((volatile long *)0x80010074)
-// bit    0 - busy / start
-// bits 4:1 - blit mode
-#define SV_BLITTER_CONTROL        ((volatile long *)0x80010078)
-// bit 0 - empty (read only)
-// bit 1 - full (read only)
-// bits 31:0 - data (write only)
-#define SV_BLITTER_FIFO           ((volatile long *)0x80010080)
-
-#ifdef USE_SV_BLITTER
-static bool isSuperBlitterLocked;
-
-static void syncSuperBlitter() {
-	// if externally locked, let the owner decide when to sync (unlock)
-	if (isSuperBlitterLocked)
-		return;
-
-	// while FIFO not empty...
-	if (superVidelFwVersion >= 9)
-		while (!(*SV_BLITTER_FIFO & 1));
-	// while busy blitting...
-	while (*SV_BLITTER_CONTROL & 1);
-}
-#endif
+static_assert(MALLOC_ALIGNMENT == 16, "MALLOC_ALIGNMENT must be == 16");
 
 #ifdef USE_MOVE16
 static inline bool hasMove16() {
@@ -72,80 +34,15 @@ static inline bool hasMove16() {
 	static bool hasMove16 = Getcookie(C__CPU, &val) == C_FOUND && val >= 40;
 	return hasMove16;
 }
-#endif
-
-void lockSuperBlitter() {
-#ifdef USE_SV_BLITTER
-	assert(!isSuperBlitterLocked);
 
-	isSuperBlitterLocked = true;
-#endif
+template<typename T>
+constexpr bool isAligned(T val) {
+	return (reinterpret_cast<uintptr>(val) & (MALLOC_ALIGNMENT - 1)) == 0;
 }
-
-void unlockSuperBlitter() {
-#ifdef USE_SV_BLITTER
-	assert(isSuperBlitterLocked);
-
-	isSuperBlitterLocked = false;
-	if (hasSuperVidel())
-		syncSuperBlitter();
 #endif
-}
-
-// see atari-graphics.cpp
-extern mspace g_mspace;
 
 namespace Graphics {
 
-constexpr size_t ALIGN = 16;	// 16 bytes
-
-// hijack surface overrides here as well as these are tightly related
-// to the blitting routine below
-void Surface::create(int16 width, int16 height, const PixelFormat &f) {
-	assert(width >= 0 && height >= 0);
-	free();
-
-	w = width;
-	h = height;
-	format = f;
-	pitch = w * format.bytesPerPixel;
-
-	if (width && height) {
-#ifdef USE_SV_BLITTER
-		if (g_mspace) {
-			pixels = mspace_calloc(g_mspace, height * pitch, f.bytesPerPixel);
-
-			if (!pixels)
-				error("Not enough memory to allocate a surface");
-
-			assert(pixels >= (void *)0xA0000000);
-		} else {
-#else
-		{
-#endif
-			pixels = ::calloc(height * pitch, f.bytesPerPixel);
-			if (!pixels)
-				error("Not enough memory to allocate a surface");
-
-			assert(((uintptr)pixels & (ALIGN - 1)) == 0);
-		}
-	}
-}
-
-void Surface::free() {
-#ifdef USE_SV_BLITTER
-	if (g_mspace)
-		mspace_free(g_mspace, pixels);
-	else
-#endif
-	if (pixels)
-		::free(pixels);
-
-	pixels = nullptr;
-	w = h = pitch = 0;
-	format = PixelFormat();
-}
-
 // Function to blit a rect (version optimized for Atari Falcon with SuperVidel's SuperBlitter)
 void copyBlit(byte *dst, const byte *src,
 			   const uint dstPitch, const uint srcPitch,
@@ -156,7 +53,7 @@ void copyBlit(byte *dst, const byte *src,
 
 #ifdef USE_SV_BLITTER
 	if (((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
-		if (superVidelFwVersion >= 9) {
+		if (g_superVidelFwVersion >= 9) {
 			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC1
 			*SV_BLITTER_FIFO = 0x00000000;				// SV_BLITTER_SRC2
 			*SV_BLITTER_FIFO = (long)dst;				// SV_BLITTER_DST
@@ -181,12 +78,12 @@ void copyBlit(byte *dst, const byte *src,
 			*SV_BLITTER_CONTROL        = 0x01;
 		}
 
-		syncSuperBlitter();
+		SyncSuperBlitter();
 	} else
 #endif
 	if (dstPitch == srcPitch && dstPitch == (w * bytesPerPixel)) {
 #ifdef USE_MOVE16
-		if (hasMove16() && ((uintptr)src & (ALIGN - 1)) == 0 && ((uintptr)dst & (ALIGN - 1)) == 0) {
+		if (hasMove16() && isAligned(src) && isAligned(dst)) {
 			__asm__ volatile(
 			"	move.l	%2,%%d0\n"
 			"	lsr.l	#4,%%d0\n"
@@ -216,8 +113,8 @@ void copyBlit(byte *dst, const byte *src,
 			"	move16	(%0)+,(%1)+\n"
 			"2:\n"
 			"	dbra	%%d0,1b\n"
-			// handle also the unlikely case when 'dstPitch'
-			// is not divisible by 16 but 'src' and 'dst' are
+			// handle also the case when 'dstPitch' is not
+			// divisible by 16 but 'src' and 'dst' are
 			"3:\n"
 			"	moveq	#0x0f,%%d0\n"
 			"	and.l	%2,%%d0\n"
@@ -252,8 +149,7 @@ void copyBlit(byte *dst, const byte *src,
 		}
 	} else {
 #ifdef USE_MOVE16
-		if (hasMove16() && ((uintptr)src & (ALIGN - 1)) == 0 && ((uintptr)dst & (ALIGN - 1)) == 0
-				&& (srcPitch & (ALIGN - 1)) == 0 && (dstPitch & (ALIGN - 1)) == 0) {
+		if (hasMove16() && isAligned(src) && isAligned(dst) && isAligned(srcPitch) && isAligned(dstPitch)) {
 			__asm__ volatile(
 			"	move.l	%2,%%d0\n"
 
diff --git a/graphics/surface.cpp b/graphics/surface.cpp
index 06899051d65..540fa4dbf79 100644
--- a/graphics/surface.cpp
+++ b/graphics/surface.cpp
@@ -137,7 +137,7 @@ void Surface::drawEllipse(int x0, int y0, int x1, int y1, uint32 color, bool fil
 		error("Surface::drawEllipse: bytesPerPixel must be 1, 2, or 4, got %d", format.bytesPerPixel);
 }
 
-// see graphics/blit/blit-atari.cpp
+// see backends/graphics/atari/atari-surface.cpp
 #ifndef ATARI
 void Surface::create(int16 width, int16 height, const PixelFormat &f) {
 	assert(width >= 0 && height >= 0);


Commit: 3dc861cf127e3824c48661418757384021f2d1aa
    https://github.com/scummvm/scummvm/commit/3dc861cf127e3824c48661418757384021f2d1aa
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
GRAPHICS: ATARI: Add specialized keyBlitLogic

Changed paths:
    graphics/blit/blit-atari.cpp
    graphics/blit/blit.cpp


diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index 6e4540b537f..bfd45a39d4a 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -43,6 +43,55 @@ constexpr bool isAligned(T val) {
 
 namespace Graphics {
 
+// Function to blit a rect with a transparent color key
+void keyBlitLogicAtari(byte *dst, const byte *src, const uint w, const uint h,
+					   const uint srcDelta, const uint dstDelta, const uint32 key) {
+#ifdef USE_SV_BLITTER
+	if (key == 0 && ((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
+		if (g_superVidelFwVersion >= 9) {
+			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC1
+			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC2
+			*SV_BLITTER_FIFO = (long)dst;				// SV_BLITTER_DST
+			*SV_BLITTER_FIFO = w - 1;					// SV_BLITTER_COUNT
+			*SV_BLITTER_FIFO = srcDelta + w;			// SV_BLITTER_SRC1_OFFSET
+			*SV_BLITTER_FIFO = srcDelta + w;			// SV_BLITTER_SRC2_OFFSET
+			*SV_BLITTER_FIFO = dstDelta + w;			// SV_BLITTER_DST_OFFSET
+			*SV_BLITTER_FIFO = h;						// SV_BLITTER_MASK_AND_LINES
+			*SV_BLITTER_FIFO = 0x03;					// SV_BLITTER_CONTROL
+		}  else {
+			// make sure the blitter is idle
+			while (*SV_BLITTER_CONTROL & 1);
+
+			*SV_BLITTER_SRC1           = (long)src;
+			*SV_BLITTER_SRC2           = (long)src;
+			*SV_BLITTER_DST            = (long)dst;
+			*SV_BLITTER_COUNT          = w - 1;
+			*SV_BLITTER_SRC1_OFFSET    = srcDelta + w;
+			*SV_BLITTER_SRC2_OFFSET    = srcDelta + w;
+			*SV_BLITTER_DST_OFFSET     = dstDelta + w;
+			*SV_BLITTER_MASK_AND_LINES = h;
+			*SV_BLITTER_CONTROL        = 0x03;
+		}
+
+		SyncSuperBlitter();
+	} else
+#endif
+	{
+		for (uint y = 0; y < h; ++y) {
+			for (uint x = 0; x < w; ++x) {
+				const uint32 color = *src++;
+				if (color != key)
+					*dst++ = color;
+				else
+					dst++;
+			}
+
+			src += srcDelta;
+			dst += dstDelta;
+		}
+	}
+}
+
 // Function to blit a rect (version optimized for Atari Falcon with SuperVidel's SuperBlitter)
 void copyBlit(byte *dst, const byte *src,
 			   const uint dstPitch, const uint srcPitch,
diff --git a/graphics/blit/blit.cpp b/graphics/blit/blit.cpp
index 6b73aa4610f..0d42547efc6 100644
--- a/graphics/blit/blit.cpp
+++ b/graphics/blit/blit.cpp
@@ -26,7 +26,10 @@
 namespace Graphics {
 
 // see graphics/blit/blit-atari.cpp
-#ifndef ATARI
+#ifdef ATARI
+extern void keyBlitLogicAtari(byte *dst, const byte *src, const uint w, const uint h,
+							  const uint srcDelta, const uint dstDelta, const uint32 key);
+#else
 // Function to blit a rect
 void copyBlit(byte *dst, const byte *src,
 				const uint dstPitch, const uint srcPitch,
@@ -83,6 +86,14 @@ inline void keyBlitLogic(byte *dst, const byte *src, const uint w, const uint h,
 	}
 }
 
+#ifdef ATARI
+template<>
+inline void keyBlitLogic<uint8, 1>(byte *dst, const byte *src, const uint w, const uint h,
+								   const uint srcDelta, const uint dstDelta, const uint32 key) {
+	keyBlitLogicAtari(dst, src, w, h, srcDelta, dstDelta, key);
+}
+#endif
+
 } // End of anonymous namespace
 
 // Function to blit a rect with a transparent color key


Commit: 3dd96ec7c5f24dbcb97b076900f6ecb36f6d36ed
    https://github.com/scummvm/scummvm/commit/3dd96ec7c5f24dbcb97b076900f6ecb36f6d36ed
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
BACKENDS: ATARI: Use hardware-accelerated cursor blitting

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-supervidel.cpp
    backends/graphics/atari/atari-supervidel.h
    backends/graphics/atari/atari-surface.cpp
    backends/graphics/atari/atari-surface.h
    graphics/blit/blit-atari.cpp


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 7e04cf00341..7069fb49c20 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -27,11 +27,31 @@
 #include "atari-surface.h"
 //#include "backends/platform/atari/atari-debug.h"
 
-byte Cursor::_palette[256*3] = {};
+bool Cursor::_globalSurfaceChanged;
+
+byte Cursor::_palette[256*3];
+
+const byte *Cursor::_buf;
+int Cursor::_width;
+int Cursor::_height;
+int Cursor::_hotspotX;
+int Cursor::_hotspotY;
+uint32 Cursor::_keycolor;
+
+Graphics::Surface Cursor::_surface;
+Graphics::Surface Cursor::_surfaceMask;
 
 Cursor::Cursor(const AtariGraphicsManager *manager, const Screen *screen)
-		: _manager(manager)
-		, _parentScreen(screen) {
+	: _manager(manager)
+	, _parentScreen(screen) {
+}
+
+Cursor::~Cursor() {
+	_savedBackground.free();
+	// beware, called multiple times (they have to be destroyed before
+	// AtariSurfaceDeinit() is called)
+	_surface.free();
+	_surfaceMask.free();
 }
 
 void Cursor::update() {
@@ -98,7 +118,7 @@ void Cursor::updatePosition(int deltaX, int deltaY) {
 	_positionChanged = true;
 }
 
-void Cursor::setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor) {
+/* static */ void Cursor::setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor) {
 	if (w == 0 || h == 0 || buf == nullptr) {
 		_buf = nullptr;
 		return;
@@ -111,79 +131,97 @@ void Cursor::setSurface(const void *buf, int w, int h, int hotspotX, int hotspot
 	_hotspotY = hotspotY;
 	_keycolor = keycolor;
 
-	_surfaceChanged = true;
+	_globalSurfaceChanged = true;
 }
 
-void Cursor::setPalette(const byte *colors, uint start, uint num) {
+/* static */ void Cursor::setPalette(const byte *colors, uint start, uint num) {
 	memcpy(&_palette[start * 3], colors, num * 3);
 
-	_surfaceChanged = true;
+	_globalSurfaceChanged = true;
 }
 
 void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
-	const int cursorWidth = (_srcRect.width() + 15) & (-16);
+	static int rShift, gShift, bShift;
+	static int rMask, gMask, bMask;
+
+	// TODO: maintain a max width
+	const int cursorWidth = g_hasSuperVidel ? _width : ((_srcRect.width() + 15) & (-16));
 	const int cursorHeight = _height;
 	const bool isCLUT8 = format.isCLUT8();
 
 	if (_surface.w != cursorWidth || _surface.h != cursorHeight || _surface.format != format) {
 		if (!isCLUT8 && _surface.format != format) {
-			_rShift = format.rLoss - format.rShift;
-			_gShift = format.gLoss - format.gShift;
-			_bShift = format.bLoss - format.bShift;
+			rShift = format.rLoss - format.rShift;
+			gShift = format.gLoss - format.gShift;
+			bShift = format.bLoss - format.bShift;
 
-			_rMask = format.rMax() << format.rShift;
-			_gMask = format.gMax() << format.gShift;
-			_bMask = format.bMax() << format.bShift;
+			rMask = format.rMax() << format.rShift;
+			gMask = format.gMax() << format.gShift;
+			bMask = format.bMax() << format.bShift;
 		}
 
-		_surface.create(cursorWidth, cursorHeight, format);
-		_surfaceMask.create(_surface.w / 8, _surface.h, format);	// 1 bpl
+		_surface.create(cursorWidth, cursorHeight, format);	// keep it 8bpl even if bitsPerPixel == 4...
+		_surfaceMask.create(g_hasSuperVidel ? _surface.w : _surface.w / 8, _surface.h, format);	// 1 bpl
 	}
 
-	const int srcRectWidth = _srcRect.width();
+	const int srcRectWidth = g_hasSuperVidel ? _width : _srcRect.width();
 
-	const byte *src = _buf + _srcRect.left;
+	const byte *src = g_hasSuperVidel ? _buf : _buf + _srcRect.left;
 	byte *dst = (byte *)_surface.getPixels();
-	uint16 *dstMask = (uint16 *)_surfaceMask.getPixels();
+	byte *dstMask = (byte *)_surfaceMask.getPixels();
+	uint16 *dstMask16 = (uint16 *)_surfaceMask.getPixels();
 	const int srcPadding = _width - srcRectWidth;
 	const int dstPadding = _surface.w - srcRectWidth;
 
+	uint16 mask16 = 0xffff;
+	uint16 invertedBit = 0x7fff;
+
 	for (int j = 0; j < cursorHeight; ++j) {
 		for (int i = 0; i < srcRectWidth; ++i) {
 			const uint32 color = *src++;
-			const uint16 bit = 1 << (15 - (i % 16));
 
 			if (color != _keycolor) {
 				if (!isCLUT8) {
 					// Convert CLUT8 to RGB332/RGB121 palette
-					*dst++ = ((_palette[color*3 + 0] >> _rShift) & _rMask)
-						   | ((_palette[color*3 + 1] >> _gShift) & _gMask)
-						   | ((_palette[color*3 + 2] >> _bShift) & _bMask);
+					*dst++ =  ((_palette[color*3 + 0] >> rShift) & rMask)
+							 | ((_palette[color*3 + 1] >> gShift) & gMask)
+							 | ((_palette[color*3 + 2] >> bShift) & bMask);
 				} else {
 					*dst++ = color;
 				}
 
-				// clear bit
-				*dstMask &= ~bit;
+				if (g_hasSuperVidel)
+					*dstMask++ = 0xff;
+				else
+					mask16 &= invertedBit;
 			} else {
 				*dst++ = 0x00;
 
-				// set bit
-				*dstMask |= bit;
+				if (g_hasSuperVidel)
+					*dstMask++ = 0x00;
+			}
+
+			if (!g_hasSuperVidel && invertedBit == 0xfffe) {
+				*dstMask16++ = mask16;
+				mask16 = 0xffff;
 			}
 
-			if (bit == 0x0001)
-				dstMask++;
+			// ror.w #1,invertedBit
+			invertedBit = (invertedBit >> 1) | (invertedBit << (sizeof (invertedBit) * 8 - 1));
 		}
 
 		src += srcPadding;
 
 		if (dstPadding) {
+			assert(!g_hasSuperVidel);
+
+			// this is at most 15 pixels
 			memset(dst, 0x00, dstPadding);
 			dst += dstPadding;
 
-			*dstMask |= ((1 << dstPadding) - 1);
-			dstMask++;
+			*dstMask16++ = mask16;
+			mask16 = 0xffff;
+			invertedBit = 0x7fff;
 		}
 	}
 }
@@ -220,7 +258,7 @@ void Cursor::saveBackground() {
 
 	//atari_debug("Cursor::saveBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
 
-	// save native pixels (i.e. bitplanes)
+	// save native bitplanes or pixels, so it must be a Graphics::Surface to copy from
 	if (_savedBackground.w != _savedRect.width()
 		|| _savedBackground.h != _savedRect.height()
 		|| _savedBackground.format != dstSurface.format) {
@@ -236,13 +274,13 @@ void Cursor::draw() {
 
 	//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
 
-	if (_surfaceChanged || _srcRect.width() != _previousSrcRect.width()) {
+	if (_globalSurfaceChanged || _srcRect.width() != _previousSrcRect.width()) {
 		_previousSrcRect = _srcRect;
 
 		convertSurfaceTo(dstSurface.format);
 
 		if (!g_hasSuperVidel) {
-			// C2P in-place (TODO: merge with convertSurfaceTo)
+			// C2P in-place
 			AtariSurface surf(dstBitsPerPixel);
 			surf.w = _surface.w;
 			surf.h = _surface.h;
@@ -255,14 +293,17 @@ void Cursor::draw() {
 				0, 0,
 				Common::Rect(_surface.w, _surface.h));
 		}
+
+		_globalSurfaceChanged = false;
 	}
 
-	// don't use _srcRect.right as 'x2' as this must be aligned first
-	// (_surface.w is recalculated thanks to convertSurfaceTo())
 	dstSurface.drawMaskedSprite(
 		_surface, _surfaceMask,
 		_dstRect.left + _xOffset, _dstRect.top,
-		Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
+		g_hasSuperVidel
+			? _srcRect
+			// TODO: _srcRect and add clipping to AtariSurface::drawMaskedSprite
+			: Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
 
 	_visibilityChanged = _positionChanged = _surfaceChanged = false;
 }
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 3bbb56b4ecc..7f07940beb8 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -23,7 +23,6 @@
 #define BACKENDS_GRAPHICS_ATARI_CURSOR_H
 
 #include "graphics/surface.h"
-//#include "backends/platform/atari/atari-debug.h"
 
 class AtariGraphicsManager;
 struct Screen;
@@ -36,6 +35,7 @@ struct Screen;
 
 struct Cursor {
 	Cursor(const AtariGraphicsManager *manager, const Screen *screen);
+	~Cursor();
 
 	void reset(const Graphics::Surface *boundingSurf, int xOffset) {
 		_boundingSurf = boundingSurf;
@@ -65,6 +65,9 @@ struct Cursor {
 
 		return last;
 	}
+	void setSurfaceChanged() {
+		_surfaceChanged = true;
+	}
 
 	// position
 	Common::Point getPosition() const {
@@ -84,9 +87,8 @@ struct Cursor {
 	void updatePosition(int deltaX, int deltaY);
 
 	// 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 convertSurfaceTo(const Graphics::PixelFormat &format);
+	static void setSurface(const void *buf, int w, int h, int hotspotX, int hotspotY, uint32 keycolor);
+	static void setPalette(const byte *colors, uint start, uint num);
 
 	bool isVisible() const {
 		return !_outOfScreen && _visible;
@@ -100,17 +102,16 @@ struct Cursor {
 	void draw();
 
 private:
+	void convertSurfaceTo(const Graphics::PixelFormat &format);
 	void restoreBackground();
 
-	static byte _palette[256*3];
-
 	const AtariGraphicsManager *_manager;
 	const Screen *_parentScreen;
 	const Graphics::Surface *_boundingSurf = nullptr;
 	int _xOffset = 0;
 
-	bool _positionChanged = true;
-	bool _surfaceChanged = true;
+	bool _positionChanged = false;
+	bool _surfaceChanged = false;
 	bool _visibilityChanged = false;
 
 	bool _visible = false;
@@ -126,21 +127,19 @@ private:
 	Common::Rect _alignedDstRect;
 
 	// related to 'surface'
-	const byte *_buf = nullptr;
-	int _width;
-	int _height;
-	int _hotspotX;
-	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;
-	int _rMask, _gMask, _bMask;
+	static bool _globalSurfaceChanged;
+
+	static byte _palette[256*3];
+
+	static const byte *_buf;
+	static int _width;
+	static int _height;
+	static int _hotspotX;
+	static int _hotspotY;
+	static uint32 _keycolor;
+
+	static Graphics::Surface _surface;
+	static Graphics::Surface _surfaceMask;
 };
 
 #endif // BACKENDS_GRAPHICS_ATARI_CURSOR_H
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index bdabe154b56..e51d89f8aff 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -756,6 +756,8 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
 
 	_pendingScreenChanges.setScreenSurface(_screen[kOverlayBuffer]->surf.get());
 
+	// cursor is reset before calling showOverlay()
+
 	// do not cache dirtyRects and saved cursor rect
 	_screen[kOverlayBuffer]->reset(
 		getOverlayWidth(), getOverlayHeight(),
@@ -789,6 +791,9 @@ void AtariGraphicsManager::hideOverlay() {
 	_pendingScreenChanges.setScreenSurface(
 		_screen[_currentState.mode == kTripleBuffering ? kBackBuffer2 : kFrontBuffer]->surf.get());
 
+	// reset cursor as its srcSurface has been just changed so wait for cursor surface to be updated
+	Cursor::setSurface(nullptr, 0, 0, 0, 0, 0);
+
 	_overlayState = kOverlayHidden;
 
 	if (!_pendingScreenChanges.empty()) {
@@ -984,20 +989,24 @@ void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int h
 	if (format)
 		assert(*format == PIXELFORMAT_CLUT8);
 
-	_screen[kOverlayBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
-	_screen[kFrontBuffer]->cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
+	Cursor::setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor);
+
+	_screen[kOverlayBuffer]->cursor.setSurfaceChanged();
+	_screen[kFrontBuffer]->cursor.setSurfaceChanged();
 
 	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[kBackBuffer1]->cursor.setSurfaceChanged();
+		_screen[kBackBuffer2]->cursor.setSurfaceChanged();
 	}
 }
 
 void AtariGraphicsManager::setCursorPalette(const byte *colors, uint start, uint num) {
 	atari_debug("setCursorPalette: %d, %d", start, num);
 
+	Cursor::setPalette(colors, start, num);
+
 	// cursor palette is supported only in the overlay
-	_screen[kOverlayBuffer]->cursor.setPalette(colors, start, num);
+	_screen[kOverlayBuffer]->cursor.setSurfaceChanged();
 }
 
 void AtariGraphicsManager::updateMousePosition(int deltaX, int deltaY) {
@@ -1137,9 +1146,6 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 		cursor.saveBackground();
 	}
 
-	// unlock here because cursor.draw() is a software blit
-	UnlockSuperBlitter();
-
 	if (drawCursor) {
 		cursor.draw();
 		updated |= true;
@@ -1147,6 +1153,8 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 
 	dstScreen->clearDirtyRects();
 
+	UnlockSuperBlitter();
+
 	return updated;
 }
 
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index 06801215386..b180bddb3f5 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -35,6 +35,7 @@ Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graph
 
 	const int bitsPerPixel = _manager->getBitsPerPixel(format);
 
+#ifdef USE_SUPERVIDEL
 	if (g_hasSuperVidel) {
 		surf.reset(new SuperVidelSurface(
 			width + 2 * MAX_HZ_SHAKE,
@@ -42,7 +43,9 @@ Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graph
 			format,
 			bitsPerPixel));
 		_offsettedSurf.reset(new SuperVidelSurface(bitsPerPixel));
-	} else {
+	} else
+#endif
+	{
 		surf.reset(new AtariSurface(
 			width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE),
 			height + 2 * MAX_V_SHAKE,
diff --git a/backends/graphics/atari/atari-supervidel.cpp b/backends/graphics/atari/atari-supervidel.cpp
index d9bfef5ac98..e4ca55c0e19 100644
--- a/backends/graphics/atari/atari-supervidel.cpp
+++ b/backends/graphics/atari/atari-supervidel.cpp
@@ -29,6 +29,7 @@ bool g_hasSuperVidel = false;
 
 #ifdef USE_SV_BLITTER
 int g_superVidelFwVersion = 0;
+const byte *g_blitMask = nullptr;
 
 static bool isSuperBlitterLocked;
 
diff --git a/backends/graphics/atari/atari-supervidel.h b/backends/graphics/atari/atari-supervidel.h
index c2725c4d718..90aa9e0f459 100644
--- a/backends/graphics/atari/atari-supervidel.h
+++ b/backends/graphics/atari/atari-supervidel.h
@@ -22,6 +22,8 @@
 #ifndef BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
 #define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
 
+#include "common/scummsys.h"
+
 #ifdef USE_SUPERVIDEL
 
 // bits 26:0
@@ -48,6 +50,7 @@
 
 #ifdef USE_SV_BLITTER
 extern int g_superVidelFwVersion;
+extern const byte *g_blitMask;
 
 void SyncSuperBlitter();
 #endif	// USE_SV_BLITTER
diff --git a/backends/graphics/atari/atari-surface.cpp b/backends/graphics/atari/atari-surface.cpp
index efa9dcc9c0e..cb52f21d153 100644
--- a/backends/graphics/atari/atari-surface.cpp
+++ b/backends/graphics/atari/atari-surface.cpp
@@ -233,51 +233,6 @@ void AtariSurface::drawMaskedSprite(
 	}
 }
 
-void SuperVidelSurface::drawMaskedSprite(
-	const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
-	int destX, int destY,
-	const Common::Rect &subRect) {
-	assert(subRect.width() % 16 == 0);
-	assert(subRect.width() == srcSurface.w);
-	assert(srcSurface.format == format);
-	assert(_bitsPerPixel == 8);
-
-	const byte *src = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
-	const uint16 *mask = (const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top);
-	byte *dst = (byte *)getBasePtr(destX, destY);
-
-	const int height = subRect.height();
-	const int width = subRect.width();
-	const int dstOffset = pitch - width;
-
-	for (int j = 0; j < height; ++j) {
-		for (int i = 0; i < width; i += 16, mask++) {
-			const uint16 m = *mask;
-
-			if (m == 0xFFFF) {
-				// all 16 pixels transparent
-				src += 16;
-				dst += 16;
-				continue;
-			}
-
-			for (int k = 0; k < 16; ++k) {
-				const uint16 bit = 1 << (15 - k);
-
-				if (m & bit) {
-					// transparent
-					src++;
-					dst++;
-				} else {
-					*dst++ = *src++;
-				}
-			}
-		}
-
-		dst += dstOffset;
-	}
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef USE_SUPERVIDEL
diff --git a/backends/graphics/atari/atari-surface.h b/backends/graphics/atari/atari-surface.h
index 62bcca36883..82198a29223 100644
--- a/backends/graphics/atari/atari-surface.h
+++ b/backends/graphics/atari/atari-surface.h
@@ -24,6 +24,8 @@
 
 #include "graphics/managed_surface.h"
 
+#include "backends/graphics/atari/atari-supervidel.h"
+
 class AtariSurface : public Graphics::ManagedSurface {
 public:
 	AtariSurface(int bitsPerPixel);
@@ -56,6 +58,7 @@ protected:
 	int _bitsPerPixel = 0;
 };
 
+#ifdef USE_SUPERVIDEL
 class SuperVidelSurface final : public AtariSurface {
 public:
 	SuperVidelSurface(int bitsPerPixel)
@@ -75,8 +78,17 @@ public:
 
 	void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
 						  int destX, int destY,
-						  const Common::Rect &subRect) override;
+						  const Common::Rect &subRect) override {
+#ifdef USE_SV_BLITTER
+		g_blitMask = (const byte *)srcMask.getBasePtr(subRect.left, subRect.top);
+#endif
+		copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, 0);
+#ifdef USE_SV_BLITTER
+		g_blitMask = nullptr;
+#endif
+	}
 };
+#endif
 
 void AtariSurfaceInit();
 void AtariSurfaceDeinit();
diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index bfd45a39d4a..15e266990a7 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -50,7 +50,7 @@ void keyBlitLogicAtari(byte *dst, const byte *src, const uint w, const uint h,
 	if (key == 0 && ((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
 		if (g_superVidelFwVersion >= 9) {
 			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC1
-			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC2
+			*SV_BLITTER_FIFO = (long)(g_blitMask ? g_blitMask : src);	// SV_BLITTER_SRC2
 			*SV_BLITTER_FIFO = (long)dst;				// SV_BLITTER_DST
 			*SV_BLITTER_FIFO = w - 1;					// SV_BLITTER_COUNT
 			*SV_BLITTER_FIFO = srcDelta + w;			// SV_BLITTER_SRC1_OFFSET
@@ -63,7 +63,7 @@ void keyBlitLogicAtari(byte *dst, const byte *src, const uint w, const uint h,
 			while (*SV_BLITTER_CONTROL & 1);
 
 			*SV_BLITTER_SRC1           = (long)src;
-			*SV_BLITTER_SRC2           = (long)src;
+			*SV_BLITTER_SRC2           = (long)(g_blitMask ? g_blitMask : src);
 			*SV_BLITTER_DST            = (long)dst;
 			*SV_BLITTER_COUNT          = w - 1;
 			*SV_BLITTER_SRC1_OFFSET    = srcDelta + w;


Commit: fbbecd55f38fdc1a6c839ebcde37b0514662fc98
    https://github.com/scummvm/scummvm/commit/fbbecd55f38fdc1a6c839ebcde37b0514662fc98
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:34+02:00

Commit Message:
GRAPHICS: Make Graphics::PixelFormat::createFormatCLUT8 constexpr

Changed paths:
    graphics/pixelformat.h


diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h
index e2609e84b9f..6b1b12fe040 100644
--- a/graphics/pixelformat.h
+++ b/graphics/pixelformat.h
@@ -181,7 +181,7 @@ struct PixelFormat {
 	}
 
 	/** Define a CLUT8 pixel format. */
-	static inline PixelFormat createFormatCLUT8() {
+	static constexpr inline PixelFormat createFormatCLUT8() {
 		return PixelFormat(1, 0, 0, 0, 0, 0, 0, 0, 0);
 	}
 


Commit: 0520570a7b6f31ab419dcbe5a8cd5094a56c97d5
    https://github.com/scummvm/scummvm/commit/0520570a7b6f31ab419dcbe5a8cd5094a56c97d5
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Move getBitsPerPixel from AtariGraphicsManager to AtariSurface

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-graphics.h
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-surface.cpp
    backends/graphics/atari/atari-surface.h


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 7069fb49c20..6b7b3e02983 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -78,7 +78,7 @@ void Cursor::update() {
 		assert(_srcRect.width() == _dstRect.width());
 		assert(_srcRect.height() == _dstRect.height());
 
-		const int dstBitsPerPixel = _manager->getBitsPerPixel(_parentScreen->offsettedSurf->format);
+		const int dstBitsPerPixel = _parentScreen->offsettedSurf->getBitsPerPixel();
 
 		// non-direct rendering never uses 4bpp but maybe in the future ...
 		_savedRect = _manager->alignRect(
@@ -269,8 +269,8 @@ void Cursor::saveBackground() {
 }
 
 void Cursor::draw() {
-	auto &dstSurface          = *_parentScreen->offsettedSurf;
-	const int dstBitsPerPixel = _manager->getBitsPerPixel(dstSurface.format);
+	AtariSurface &dstSurface  = *_parentScreen->offsettedSurf;
+	const int dstBitsPerPixel = dstSurface.getBitsPerPixel();
 
 	//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
 
@@ -281,7 +281,7 @@ void Cursor::draw() {
 
 		if (!g_hasSuperVidel) {
 			// C2P in-place
-			AtariSurface surf(dstBitsPerPixel);
+			AtariSurface surf;
 			surf.w = _surface.w;
 			surf.h = _surface.h;
 			surf.pitch = _surface.pitch * dstBitsPerPixel / 8;	// 4bpp is not byte per pixel anymore
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index e51d89f8aff..fc2bbfa49af 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -41,10 +41,6 @@
 
 #define SCREEN_ACTIVE
 
-static const Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::createFormatCLUT8();
-static const Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
-static const Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
-
 static void shrinkVidelVisibleArea() {
 	// Active VGA screen area consists of 960 half-lines, i.e. 480 raster lines.
 	// In case of 320x240, the number is still 480 but data is fetched
@@ -1076,10 +1072,6 @@ 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);
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 449bbfe5c89..6406e0381c2 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -123,7 +123,6 @@ private:
 		kActionToggleAspectRatioCorrection = 100,
 	};
 
-	int getBitsPerPixel(const Graphics::PixelFormat &format) const;
 	void allocateSurfaces();
 	void freeSurfaces();
 
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index b180bddb3f5..1d2826fa626 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -25,7 +25,6 @@
 
 #include "atari-graphics.h"
 #include "atari-supervidel.h"
-#include "atari-surface.h"
 #include "backends/platform/atari/atari-debug.h"
 
 Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
@@ -33,25 +32,21 @@ Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graph
 	, cursor(manager, this)
 	, palette(palette_) {
 
-	const int bitsPerPixel = _manager->getBitsPerPixel(format);
-
 #ifdef USE_SUPERVIDEL
 	if (g_hasSuperVidel) {
 		surf.reset(new SuperVidelSurface(
 			width + 2 * MAX_HZ_SHAKE,
 			height + 2 * MAX_V_SHAKE,
-			format,
-			bitsPerPixel));
-		_offsettedSurf.reset(new SuperVidelSurface(bitsPerPixel));
+			format));
+		_offsettedSurf.reset(new SuperVidelSurface());
 	} else
 #endif
 	{
 		surf.reset(new AtariSurface(
 			width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE),
 			height + 2 * MAX_V_SHAKE,
-			format,
-			bitsPerPixel));
-		_offsettedSurf.reset(new AtariSurface(bitsPerPixel));
+			format));
+		_offsettedSurf.reset(new AtariSurface());
 	}
 
 	_offsettedSurf->create(
@@ -73,7 +68,7 @@ void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf,
 	rez = -1;
 	mode = -1;
 
-	const int bitsPerPixel = _manager->getBitsPerPixel(surf->format);
+	const int bitsPerPixel = surf->getBitsPerPixel();
 
 	// erase old screen
 	_offsettedSurf->fillRect(_offsettedSurf->getBounds(), 0);
diff --git a/backends/graphics/atari/atari-surface.cpp b/backends/graphics/atari/atari-surface.cpp
index cb52f21d153..e204a237698 100644
--- a/backends/graphics/atari/atari-surface.cpp
+++ b/backends/graphics/atari/atari-surface.cpp
@@ -133,12 +133,7 @@ void Surface::free() {
 
 ///////////////////////////////////////////////////////////////////////////////
 
-AtariSurface::AtariSurface(int bitsPerPixel)
-	: _bitsPerPixel(bitsPerPixel) {
-}
-
-AtariSurface::AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel)
-	: _bitsPerPixel(bitsPerPixel) {
+AtariSurface::AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat) {
 	create(width, height, pixelFormat);
 }
 
@@ -150,7 +145,7 @@ void AtariSurface::create(int16 width, int16 height, const Graphics::PixelFormat
 	MemoryPool *oldPool = s_currentPool;
 	s_currentPool = &s_videoRamPool;
 
-	Graphics::ManagedSurface::create(width * _bitsPerPixel / 8, height, pixelFormat);
+	Graphics::ManagedSurface::create(width * (format == PIXELFORMAT_RGB121 ? 4 : 8) / 8, height, pixelFormat);
 	w = width;
 
 	s_currentPool = oldPool;
@@ -176,9 +171,9 @@ void AtariSurface::copyRectToSurface(const void *buffer, int srcPitch, int destX
 	const byte *pChunky    = (const byte *)buffer;
 	const byte *pChunkyEnd = pChunky + (height - 1) * srcPitch + width * format.bytesPerPixel;
 
-	byte *pScreen = (byte *)getPixels() + destY * pitch + destX * _bitsPerPixel/8;
+	byte *pScreen = (byte *)getPixels() + destY * pitch + destX * getBitsPerPixel()/8;
 
-	if (_bitsPerPixel == 8) {
+	if (getBitsPerPixel() == 8) {
 		if (srcPitch == width) {
 			if (srcPitch == pitch) {
 				asm_c2p1x1_8(pChunky, pChunkyEnd, pScreen);
@@ -218,13 +213,13 @@ void AtariSurface::drawMaskedSprite(
 	assert(subRect.width() == srcSurface.w);
 	assert(srcSurface.format == format);
 
-	if (_bitsPerPixel == 4) {
+	if (getBitsPerPixel() == 4) {
 		asm_draw_4bpl_sprite(
 			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
 			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
 			destX, destY,
 			pitch, subRect.width(), subRect.height());
-	} else if (_bitsPerPixel == 8) {
+	} else if (getBitsPerPixel() == 8) {
 		asm_draw_8bpl_sprite(
 			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
 			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
diff --git a/backends/graphics/atari/atari-surface.h b/backends/graphics/atari/atari-surface.h
index 82198a29223..20962fcbed1 100644
--- a/backends/graphics/atari/atari-surface.h
+++ b/backends/graphics/atari/atari-surface.h
@@ -26,10 +26,14 @@
 
 #include "backends/graphics/atari/atari-supervidel.h"
 
+constexpr Graphics::PixelFormat PIXELFORMAT_CLUT8  = Graphics::PixelFormat::createFormatCLUT8();
+constexpr Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
+constexpr Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
+
 class AtariSurface : public Graphics::ManagedSurface {
 public:
-	AtariSurface(int bitsPerPixel);
-	AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel);
+	AtariSurface() = default;
+	AtariSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat);
 	~AtariSurface() override;
 
 	using Graphics::ManagedSurface::create;
@@ -54,18 +58,17 @@ public:
 								  int destX, int destY,
 								  const Common::Rect &subRect);
 
-protected:
-	int _bitsPerPixel = 0;
+	int getBitsPerPixel() const {
+		return format == PIXELFORMAT_RGB121 ? 4 : 8;
+	}
 };
 
 #ifdef USE_SUPERVIDEL
 class SuperVidelSurface final : public AtariSurface {
 public:
-	SuperVidelSurface(int bitsPerPixel)
-		: AtariSurface(bitsPerPixel) {
-	}
-	SuperVidelSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat, int bitsPerPixel)
-		: AtariSurface(width, height, pixelFormat, bitsPerPixel) {
+	SuperVidelSurface() = default;
+	SuperVidelSurface(int16 width, int16 height, const Graphics::PixelFormat &pixelFormat)
+		: AtariSurface(width, height, pixelFormat) {
 	}
 
 	//using Graphics::ManagedSurface::copyRectToSurface;


Commit: ee437e2a4282e8db1bce37846dac869cb4ee3485
    https://github.com/scummvm/scummvm/commit/ee437e2a4282e8db1bce37846dac869cb4ee3485
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Move alignRect from AtariGraphicsManager to AtariSurface

And make it static.

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-graphics.h
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-surface.h


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 6b7b3e02983..5ecbe6c1214 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -81,14 +81,14 @@ void Cursor::update() {
 		const int dstBitsPerPixel = _parentScreen->offsettedSurf->getBitsPerPixel();
 
 		// non-direct rendering never uses 4bpp but maybe in the future ...
-		_savedRect = _manager->alignRect(
+		_savedRect = AtariSurface::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(
+		_alignedDstRect = AtariSurface::alignRect(
 			_dstRect.left + _xOffset,
 			_dstRect.top,
 			_dstRect.right + _xOffset,
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index fc2bbfa49af..a0a992f19cb 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -1152,7 +1152,7 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 
 void AtariGraphicsManager::copyRectToScreenInternal(AtariSurface &dstSurface,
 													const byte *buf, int pitch, int x, int y, int w, int h) {
-	const Common::Rect rect = alignRect(x, y, x + w, y + h);
+	const Common::Rect rect = AtariSurface::alignRect(x, y, x + w, y + h);
 
 	// TODO: mask the unaligned parts and copy the rest
 	buf -= (x - rect.left);	// HACK: this assumes pointer to a complete buffer
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 6406e0381c2..b517e446d93 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -156,19 +156,6 @@ private:
 
 	Graphics::Surface *lockOverlay();
 
-	Common::Rect alignRect(int x1, int y1, int x2, int y2) const {
-		// make non-virtual for performance reasons
-		return g_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 g_hasSuperVidel
-				   ? rect
-				   : Common::Rect(rect.left & (-16), rect.top, (rect.right + 15) & (-16), rect.bottom);
-	}
-
 	bool _vgaMonitor = true;
 	bool _tt = false;
 
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index 1d2826fa626..49749a4f201 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -147,13 +147,13 @@ void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int
 		dirtyRects.clear();
 		// 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));
+		dirtyRects.insert(AtariSurface::alignRect(_xOffset, 0, _xOffset + srcSurface.w, srcSurface.h));
 
 		cursor.reset(&srcSurface, _xOffset);
 
 		fullRedraw = true;
 	} else {
-		const Common::Rect alignedRect = _manager->alignRect(x + _xOffset, y, x + _xOffset + w, y + h);
+		const Common::Rect alignedRect = AtariSurface::alignRect(x + _xOffset, y, x + _xOffset + w, y + h);
 
 		dirtyRects.insert(alignedRect);
 
diff --git a/backends/graphics/atari/atari-surface.h b/backends/graphics/atari/atari-surface.h
index 20962fcbed1..7bd5df84541 100644
--- a/backends/graphics/atari/atari-surface.h
+++ b/backends/graphics/atari/atari-surface.h
@@ -61,6 +61,19 @@ public:
 	int getBitsPerPixel() const {
 		return format == PIXELFORMAT_RGB121 ? 4 : 8;
 	}
+
+	static Common::Rect alignRect(int x1, int y1, int x2, int y2) {
+		// make non-virtual for performance reasons
+		return g_hasSuperVidel
+		   ? Common::Rect(x1, y1, x2, y2)
+		   : Common::Rect(x1 & (-16), y1, (x2 + 15) & (-16), y2);
+	}
+	static Common::Rect alignRect(const Common::Rect &rect) {
+		// make non-virtual for performance reasons
+		return g_hasSuperVidel
+		   ? rect
+		   : Common::Rect(rect.left & (-16), rect.top, (rect.right + 15) & (-16), rect.bottom);
+	}
 };
 
 #ifdef USE_SUPERVIDEL


Commit: f27f045aac0bbd267d4d26605cb8d59da555e834
    https://github.com/scummvm/scummvm/commit/f27f045aac0bbd267d4d26605cb8d59da555e834
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Remove references to AtariGraphicsManager from Screen and Cursor

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-graphics.h
    backends/graphics/atari/atari-pendingscreenchanges.h
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-screen.h


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 5ecbe6c1214..b271dad7fa5 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -21,7 +21,6 @@
 
 #include "atari-cursor.h"
 
-#include "atari-graphics.h"
 #include "atari-screen.h"
 #include "atari-supervidel.h"
 #include "atari-surface.h"
@@ -41,9 +40,8 @@ uint32 Cursor::_keycolor;
 Graphics::Surface Cursor::_surface;
 Graphics::Surface Cursor::_surfaceMask;
 
-Cursor::Cursor(const AtariGraphicsManager *manager, const Screen *screen)
-	: _manager(manager)
-	, _parentScreen(screen) {
+Cursor::Cursor(const Screen *screen)
+		: _parentScreen(screen) {
 }
 
 Cursor::~Cursor() {
@@ -87,7 +85,8 @@ void Cursor::update() {
 			_dstRect.right * dstBitsPerPixel / 8,	// fake 4bpp by 8bpp's width/2
 			_dstRect.bottom);
 
-		// this is used only in flushBackground()
+		// this is used only in flushBackground() for comparison with rects
+		// passed by Screen::addDirtyRect (aligned and shifted by the same offset)
 		_alignedDstRect = AtariSurface::alignRect(
 			_dstRect.left + _xOffset,
 			_dstRect.top,
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 7f07940beb8..46c4dff8702 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -24,7 +24,6 @@
 
 #include "graphics/surface.h"
 
-class AtariGraphicsManager;
 struct Screen;
 
 // Global state consists of:
@@ -34,7 +33,7 @@ struct Screen;
 // These always get updates by ScummVM, no need to differentiate between engines and the overlay.
 
 struct Cursor {
-	Cursor(const AtariGraphicsManager *manager, const Screen *screen);
+	Cursor(const Screen *screen);
 	~Cursor();
 
 	void reset(const Graphics::Surface *boundingSurf, int xOffset) {
@@ -105,7 +104,6 @@ private:
 	void convertSurfaceTo(const Graphics::PixelFormat &format);
 	void restoreBackground();
 
-	const AtariGraphicsManager *_manager;
 	const Screen *_parentScreen;
 	const Graphics::Surface *_boundingSurf = nullptr;
 	int _xOffset = 0;
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index a0a992f19cb..b5c17c106f2 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -1074,9 +1074,9 @@ Common::Keymap *AtariGraphicsManager::getKeymap() const {
 
 void AtariGraphicsManager::allocateSurfaces() {
 	for (int i : { kFrontBuffer, kBackBuffer1, kBackBuffer2 }) {
-		_screen[i] = new Screen(this, getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8, &_palette);
+		_screen[i] = new Screen(_tt, getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8, &_palette);
 	}
-	_screen[kOverlayBuffer] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
+	_screen[kOverlayBuffer] = new Screen(_tt, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
 	// initial position
 	_screen[kOverlayBuffer]->cursor.setPosition(getOverlayWidth() / 2, getOverlayHeight() / 2);
 
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index b517e446d93..26cb3b87fb9 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -36,9 +36,7 @@
 #define MAX_V_SHAKE  16
 
 class AtariGraphicsManager final : public GraphicsManager, Common::EventObserver {
-	friend class Cursor;
 	friend class PendingScreenChanges;
-	friend class Screen;
 
 public:
 	AtariGraphicsManager();
diff --git a/backends/graphics/atari/atari-pendingscreenchanges.h b/backends/graphics/atari/atari-pendingscreenchanges.h
index 1342c877af2..c26145fbf52 100644
--- a/backends/graphics/atari/atari-pendingscreenchanges.h
+++ b/backends/graphics/atari/atari-pendingscreenchanges.h
@@ -106,7 +106,6 @@ private:
 	std::pair<int, bool> _aspectRatioCorrectionYOffset;
 	std::pair<bool, bool> _setScreenOffsets;
 	std::pair<bool, bool> _shrinkVidelVisibleArea;
-
 };
 
 #endif // ATARI-PENDINGSCREENCHANGES_H
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index 49749a4f201..0da9a47c466 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -23,14 +23,14 @@
 
 #include <mint/falcon.h>
 
-#include "atari-graphics.h"
+#include "atari-graphics.h"	// MAX_HZ_SHAKE, MAX_V_SHAKE
 #include "atari-supervidel.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)
-	, palette(palette_) {
+Screen::Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
+	: cursor(this)
+	, palette(palette_)
+	, _tt(tt) {
 
 #ifdef USE_SUPERVIDEL
 	if (g_hasSuperVidel) {
@@ -43,7 +43,7 @@ Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graph
 #endif
 	{
 		surf.reset(new AtariSurface(
-			width + (_manager->_tt ? 0 : 2 * MAX_HZ_SHAKE),
+			width + (_tt ? 0 : 2 * MAX_HZ_SHAKE),
 			height + 2 * MAX_V_SHAKE,
 			format));
 		_offsettedSurf.reset(new AtariSurface());
@@ -73,7 +73,7 @@ void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf,
 	// erase old screen
 	_offsettedSurf->fillRect(_offsettedSurf->getBounds(), 0);
 
-	if (_manager->_tt) {
+	if (_tt) {
 		if (width <= 320 && height <= 240) {
 			surf->w = 320;
 			surf->h = 240 + 2 * MAX_V_SHAKE;
@@ -88,7 +88,7 @@ void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf,
 	} else {
 		mode = VsetMode(VM_INQUIRE) & PAL;
 
-		if (_manager->_vgaMonitor) {
+		if (VgetMonitor() == MON_VGA) {
 			mode |= VGA | (bitsPerPixel == 4 ? BPS4 : (g_hasSuperVidel ? BPS8C : BPS8));
 
 			if (width <= 320 && height <= 240) {
diff --git a/backends/graphics/atari/atari-screen.h b/backends/graphics/atari/atari-screen.h
index ce7812e433a..d20b050f0e9 100644
--- a/backends/graphics/atari/atari-screen.h
+++ b/backends/graphics/atari/atari-screen.h
@@ -39,8 +39,6 @@ struct std::hash<Common::Rect>
 	}
 };
 
-class AtariGraphicsManager;
-
 class Palette {
 public:
 	void clear() {
@@ -60,7 +58,7 @@ private:
 struct Screen {
 	using DirtyRects = std::unordered_set<Common::Rect>;
 
-	Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
+	Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
 
 	void reset(int width, int height, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition);
 	// must be called before any rectangle drawing
@@ -94,8 +92,7 @@ private:
 		kRezValueTTHigh = 6		// 1280x960 at 1bpp, TT palette
 	};
 
-	const AtariGraphicsManager *_manager;
-
+	bool _tt;
 	Common::ScopedPtr<AtariSurface> _offsettedSurf;
 	int _xOffset = 0;
 };


Commit: e575d1360e81fe95b99893df1a9cb56d071608b7
    https://github.com/scummvm/scummvm/commit/e575d1360e81fe95b99893df1a9cb56d071608b7
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Make purpose of _xOffset more explicit

This also cleans up Screen::reset() a bit.

Get rid of the reset cursor flag, it's not that useful in the overlay.

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-screen.h


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index b271dad7fa5..5be9a1c741a 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -77,6 +77,7 @@ void Cursor::update() {
 		assert(_srcRect.height() == _dstRect.height());
 
 		const int dstBitsPerPixel = _parentScreen->offsettedSurf->getBitsPerPixel();
+		const int xOffset         = (_parentScreen->offsettedSurf->w - _boundingSurf->w) / 2;
 
 		// non-direct rendering never uses 4bpp but maybe in the future ...
 		_savedRect = AtariSurface::alignRect(
@@ -88,9 +89,9 @@ void Cursor::update() {
 		// this is used only in flushBackground() for comparison with rects
 		// passed by Screen::addDirtyRect (aligned and shifted by the same offset)
 		_alignedDstRect = AtariSurface::alignRect(
-			_dstRect.left + _xOffset,
+			_dstRect.left + xOffset,
 			_dstRect.top,
-			_dstRect.right + _xOffset,
+			_dstRect.right + xOffset,
 			_dstRect.bottom);
 	}
 }
@@ -270,6 +271,7 @@ void Cursor::saveBackground() {
 void Cursor::draw() {
 	AtariSurface &dstSurface  = *_parentScreen->offsettedSurf;
 	const int dstBitsPerPixel = dstSurface.getBitsPerPixel();
+	const int xOffset         = (dstSurface.w - _boundingSurf->w) / 2;
 
 	//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
 
@@ -298,7 +300,7 @@ void Cursor::draw() {
 
 	dstSurface.drawMaskedSprite(
 		_surface, _surfaceMask,
-		_dstRect.left + _xOffset, _dstRect.top,
+		_dstRect.left + xOffset, _dstRect.top,
 		g_hasSuperVidel
 			? _srcRect
 			// TODO: _srcRect and add clipping to AtariSurface::drawMaskedSprite
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 46c4dff8702..f022f13a945 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -36,9 +36,8 @@ struct Cursor {
 	Cursor(const Screen *screen);
 	~Cursor();
 
-	void reset(const Graphics::Surface *boundingSurf, int xOffset) {
+	void reset(const Graphics::Surface *boundingSurf) {
 		_boundingSurf = boundingSurf;
-		_xOffset = xOffset;
 
 		_positionChanged = true;
 		_surfaceChanged = true;
@@ -106,7 +105,6 @@ private:
 
 	const Screen *_parentScreen;
 	const Graphics::Surface *_boundingSurf = nullptr;
-	int _xOffset = 0;
 
 	bool _positionChanged = false;
 	bool _surfaceChanged = false;
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index b5c17c106f2..685f02e3c5e 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -481,10 +481,10 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
 		_chunkySurfaceOffsetted.init(_currentState.width, _currentState.height, c2pWidth,
 			_chunkySurface.getBasePtr(xOffset, 0), _currentState.format);
 
-		_screen[kFrontBuffer]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
+		_screen[kFrontBuffer]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted);
 		if (_currentState.mode > kSingleBuffering) {
-			_screen[kBackBuffer1]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
-			_screen[kBackBuffer2]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted, xOffset, true);
+			_screen[kBackBuffer1]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted);
+			_screen[kBackBuffer2]->reset(c2pWidth, _currentState.height, _chunkySurfaceOffsetted);
 		}
 
 		{
@@ -754,11 +754,7 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
 
 	// cursor is reset before calling showOverlay()
 
-	// do not cache dirtyRects and saved cursor rect
-	_screen[kOverlayBuffer]->reset(
-		getOverlayWidth(), getOverlayHeight(),
-		*lockOverlay(), 0,
-		false);
+	_screen[kOverlayBuffer]->reset(getOverlayWidth(), getOverlayHeight(), *lockOverlay());
 
 	_overlayState = kOverlayVisible;
 
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index 0da9a47c466..a6c5ba5aab6 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -58,13 +58,10 @@ Screen::Screen(bool tt, int width, int height, const Graphics::PixelFormat &form
 			width, height));
 }
 
-void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition) {
-	_xOffset = xOffset;
-
+void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf) {
 	clearDirtyRects();
-	cursor.reset(&boundingSurf, xOffset);
-	if (resetCursorPosition)
-		cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
+	cursor.reset(&boundingSurf);
+	cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
 	rez = -1;
 	mode = -1;
 
@@ -140,6 +137,10 @@ void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int
 	if (fullRedraw)
 		return;
 
+	// x,y are relative to srcSurface but screen's width is always aligned to 16 bytes
+	// so both dirty rects and cursor must be drawn in its coordinates
+	const int xOffset = (_offsettedSurf->w - srcSurface.w) / 2;
+
 	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);
@@ -147,13 +148,13 @@ void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int
 		dirtyRects.clear();
 		// 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(AtariSurface::alignRect(_xOffset, 0, _xOffset + srcSurface.w, srcSurface.h));
+		dirtyRects.insert(AtariSurface::alignRect(xOffset, 0, xOffset + srcSurface.w, srcSurface.h));
 
-		cursor.reset(&srcSurface, _xOffset);
+		cursor.reset(&srcSurface);
 
 		fullRedraw = true;
 	} else {
-		const Common::Rect alignedRect = AtariSurface::alignRect(x + _xOffset, y, x + _xOffset + w, y + h);
+		const Common::Rect alignedRect = AtariSurface::alignRect(x + xOffset, y, x + xOffset + w, y + h);
 
 		dirtyRects.insert(alignedRect);
 
diff --git a/backends/graphics/atari/atari-screen.h b/backends/graphics/atari/atari-screen.h
index d20b050f0e9..20f5cfeb6aa 100644
--- a/backends/graphics/atari/atari-screen.h
+++ b/backends/graphics/atari/atari-screen.h
@@ -60,7 +60,7 @@ struct Screen {
 
 	Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
 
-	void reset(int width, int height, const Graphics::Surface &boundingSurf, int xOffset, bool resetCursorPosition);
+	void reset(int width, int height, const Graphics::Surface &boundingSurf);
 	// must be called before any rectangle drawing
 	void addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering);
 
@@ -94,7 +94,6 @@ private:
 
 	bool _tt;
 	Common::ScopedPtr<AtariSurface> _offsettedSurf;
-	int _xOffset = 0;
 };
 
 #endif // BACKENDS_GRAPHICS_ATARI_SCREEN_H


Commit: 3f47c7a8ced0fc302e9bf88393c26919fae71937
    https://github.com/scummvm/scummvm/commit/3f47c7a8ced0fc302e9bf88393c26919fae71937
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Let Cursor access only AtariSurface instead of Screen

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics.cpp
    backends/graphics/atari/atari-graphics.h
    backends/graphics/atari/atari-screen.cpp
    backends/graphics/atari/atari-surface.cpp
    graphics/blit/blit-atari.cpp


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index 5be9a1c741a..daee5389246 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -21,7 +21,6 @@
 
 #include "atari-cursor.h"
 
-#include "atari-screen.h"
 #include "atari-supervidel.h"
 #include "atari-surface.h"
 //#include "backends/platform/atari/atari-debug.h"
@@ -40,16 +39,14 @@ uint32 Cursor::_keycolor;
 Graphics::Surface Cursor::_surface;
 Graphics::Surface Cursor::_surfaceMask;
 
-Cursor::Cursor(const Screen *screen)
-		: _parentScreen(screen) {
-}
-
 Cursor::~Cursor() {
 	_savedBackground.free();
 	// beware, called multiple times (they have to be destroyed before
 	// AtariSurfaceDeinit() is called)
-	_surface.free();
-	_surfaceMask.free();
+	if (_surface.getPixels())
+		_surface.free();
+	if (_surface.getPixels())
+		_surfaceMask.free();
 }
 
 void Cursor::update() {
@@ -76,8 +73,8 @@ void Cursor::update() {
 		assert(_srcRect.width() == _dstRect.width());
 		assert(_srcRect.height() == _dstRect.height());
 
-		const int dstBitsPerPixel = _parentScreen->offsettedSurf->getBitsPerPixel();
-		const int xOffset         = (_parentScreen->offsettedSurf->w - _boundingSurf->w) / 2;
+		const int dstBitsPerPixel = _screenSurf->getBitsPerPixel();
+		const int xOffset         = (_screenSurf->w - _boundingSurf->w) / 2;
 
 		// non-direct rendering never uses 4bpp but maybe in the future ...
 		_savedRect = AtariSurface::alignRect(
@@ -160,8 +157,12 @@ void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
 			bMask = format.bMax() << format.bShift;
 		}
 
-		_surface.create(cursorWidth, cursorHeight, format);	// keep it 8bpl even if bitsPerPixel == 4...
-		_surfaceMask.create(g_hasSuperVidel ? _surface.w : _surface.w / 8, _surface.h, format);	// 1 bpl
+		// always 8-bit as this is both 8-bit src and 4-bit dst for C2P
+		_surface.create(cursorWidth, cursorHeight, format);
+		assert(_surface.pitch == _surface.w);
+		// always 8-bit or 1-bit
+		_surfaceMask.create(g_hasSuperVidel ? _surface.w : _surface.w / 8, _surface.h, PIXELFORMAT_CLUT8);
+		_surfaceMask.w = _surface.w;
 	}
 
 	const int srcRectWidth = g_hasSuperVidel ? _width : _srcRect.width();
@@ -254,7 +255,7 @@ void Cursor::saveBackground() {
 
 	// as this is used only for direct rendering, we don't need to worry about offsettedSurf
 	// having different dimensions than the source surface
-	const Graphics::Surface &dstSurface = *_parentScreen->offsettedSurf;
+	const Graphics::Surface &dstSurface = *_screenSurf;
 
 	//atari_debug("Cursor::saveBackground: %d %d %d %d", _savedRect.left, _savedRect.top, _savedRect.width(), _savedRect.height());
 
@@ -269,7 +270,7 @@ void Cursor::saveBackground() {
 }
 
 void Cursor::draw() {
-	AtariSurface &dstSurface  = *_parentScreen->offsettedSurf;
+	AtariSurface &dstSurface  = *_screenSurf;
 	const int dstBitsPerPixel = dstSurface.getBitsPerPixel();
 	const int xOffset         = (dstSurface.w - _boundingSurf->w) / 2;
 
@@ -319,7 +320,7 @@ void Cursor::restoreBackground() {
 
 	// 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->surfacePtr();
+	Graphics::Surface &dstSurface = *_screenSurf->surfacePtr();
 
 	// restore native bitplanes or pixels, so it must be a Graphics::Surface to copy to
 	dstSurface.copyRectToSurface(
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index f022f13a945..4d5ed0c1d15 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -24,7 +24,7 @@
 
 #include "graphics/surface.h"
 
-struct Screen;
+class AtariSurface;
 
 // Global state consists of:
 //	- palette (used for the overlay only atm)
@@ -33,10 +33,10 @@ struct Screen;
 // These always get updates by ScummVM, no need to differentiate between engines and the overlay.
 
 struct Cursor {
-	Cursor(const Screen *screen);
 	~Cursor();
 
-	void reset(const Graphics::Surface *boundingSurf) {
+	void reset(AtariSurface* screenSurf, const Graphics::Surface *boundingSurf) {
+		_screenSurf = screenSurf;
 		_boundingSurf = boundingSurf;
 
 		_positionChanged = true;
@@ -103,7 +103,7 @@ private:
 	void convertSurfaceTo(const Graphics::PixelFormat &format);
 	void restoreBackground();
 
-	const Screen *_parentScreen;
+	AtariSurface *_screenSurf;
 	const Graphics::Surface *_boundingSurf = nullptr;
 
 	bool _positionChanged = false;
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 685f02e3c5e..ab685248f58 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -25,16 +25,13 @@
 
 #include <mint/cookie.h>
 #include <mint/falcon.h>
-#include <mint/osbind.h>
 #include <mint/sysvars.h>
 
 #include "backends/platform/atari/atari-debug.h"
 #include "backends/keymapper/action.h"
 #include "backends/keymapper/keymap.h"
 #include "common/config-manager.h"
-#include "common/str.h"
 #include "common/translation.h"
-#include "engines/engine.h"
 #include "gui/ThemeEngine.h"
 
 #include "atari-surface.h"
@@ -581,7 +578,7 @@ void AtariGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, i
 		directRendering);
 
 	if (directRendering && !g_hasSuperVidel) {
-		copyRectToScreenInternal(
+		copyRectToAtariSurface(
 			*_screen[kFrontBuffer]->offsettedSurf,
 			(const byte *)buf, pitch, x, y, w, h);
 	} else {
@@ -912,7 +909,7 @@ void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x,
 		directRendering);
 
 	if (directRendering) {
-		copyRectToScreenInternal(
+		copyRectToAtariSurface(
 			*_screen[kOverlayBuffer]->offsettedSurf,
 			(const byte *)buf, pitch, x, y, w, h);
 	} else {
@@ -1146,8 +1143,8 @@ bool AtariGraphicsManager::updateScreenInternal(Screen *dstScreen, const Graphic
 	return updated;
 }
 
-void AtariGraphicsManager::copyRectToScreenInternal(AtariSurface &dstSurface,
-													const byte *buf, int pitch, int x, int y, int w, int h) {
+void AtariGraphicsManager::copyRectToAtariSurface(AtariSurface &dstSurface,
+												  const byte *buf, int pitch, int x, int y, int w, int h) {
 	const Common::Rect rect = AtariSurface::alignRect(x, y, x + w, y + h);
 
 	// TODO: mask the unaligned parts and copy the rest
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 26cb3b87fb9..fa4c3edfc28 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -135,8 +135,8 @@ private:
 	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(AtariSurface &dstSurface,
-								  const byte *buf, int pitch, int x, int y, int w, int h);
+	void copyRectToAtariSurface(AtariSurface &dstSurface,
+								const byte *buf, int pitch, int x, int y, int w, int h);
 
 	bool isOverlayDirectRendering() const {
 #ifndef DISABLE_FANCY_THEMES
diff --git a/backends/graphics/atari/atari-screen.cpp b/backends/graphics/atari/atari-screen.cpp
index a6c5ba5aab6..9df7b421add 100644
--- a/backends/graphics/atari/atari-screen.cpp
+++ b/backends/graphics/atari/atari-screen.cpp
@@ -23,13 +23,12 @@
 
 #include <mint/falcon.h>
 
-#include "atari-graphics.h"	// MAX_HZ_SHAKE, MAX_V_SHAKE
-#include "atari-supervidel.h"
-#include "backends/platform/atari/atari-debug.h"
+#include "atari-graphics.h"		// MAX_HZ_SHAKE, MAX_V_SHAKE
+#include "atari-supervidel.h"	// g_hasSuperVidel
+//#include "backends/platform/atari/atari-debug.h"
 
 Screen::Screen(bool tt, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
-	: cursor(this)
-	, palette(palette_)
+	: palette(palette_)
 	, _tt(tt) {
 
 #ifdef USE_SUPERVIDEL
@@ -60,8 +59,7 @@ Screen::Screen(bool tt, int width, int height, const Graphics::PixelFormat &form
 
 void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf) {
 	clearDirtyRects();
-	cursor.reset(&boundingSurf);
-	cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
+
 	rez = -1;
 	mode = -1;
 
@@ -131,29 +129,31 @@ void Screen::reset(int width, int height, const Graphics::Surface &boundingSurf)
 				(surf->w - width) / 2,		// left
 				(surf->h - height) / 2),	// top
 			width, height));
+
+	cursor.reset(_offsettedSurf.get(), &boundingSurf);
+	cursor.setPosition(boundingSurf.w / 2, boundingSurf.h / 2);
 }
 
 void Screen::addDirtyRect(const Graphics::Surface &srcSurface, int x, int y, int w, int h, bool directRendering) {
 	if (fullRedraw)
 		return;
 
-	// x,y are relative to srcSurface but screen's width is always aligned to 16 bytes
-	// so both dirty rects and cursor must be drawn in its coordinates
-	const int xOffset = (_offsettedSurf->w - srcSurface.w) / 2;
-
 	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();
-		// 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(AtariSurface::alignRect(xOffset, 0, xOffset + srcSurface.w, srcSurface.h));
+		// even if srcSurface.w != _offsettedSurf.w, alignRect would lead to the same result
+		dirtyRects.insert(_offsettedSurf->getBounds());
 
-		cursor.reset(&srcSurface);
+		cursor.reset(_offsettedSurf.get(), &srcSurface);
 
 		fullRedraw = true;
 	} else {
+		// x,y are relative to srcSurface but screen's width is always aligned to 16 bytes
+		// so both dirty rects and cursor must be drawn in screen coordinates
+		const int xOffset = (_offsettedSurf->w - srcSurface.w) / 2;
+
 		const Common::Rect alignedRect = AtariSurface::alignRect(x + xOffset, y, x + xOffset + w, y + h);
 
 		dirtyRects.insert(alignedRect);
diff --git a/backends/graphics/atari/atari-surface.cpp b/backends/graphics/atari/atari-surface.cpp
index e204a237698..992293815db 100644
--- a/backends/graphics/atari/atari-surface.cpp
+++ b/backends/graphics/atari/atari-surface.cpp
@@ -163,15 +163,12 @@ void AtariSurface::free() {
 void AtariSurface::copyRectToSurface(const void *buffer, int srcPitch, int destX, int destY, int width, int height) {
 	assert(width % 16 == 0);
 	assert(destX % 16 == 0);
+	assert(format.bytesPerPixel == 1);
 
-	// '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*
-	// 2. (subRect.right, subRect.bottom) = even worse, end of the *next* line, not current one
 	const byte *pChunky    = (const byte *)buffer;
-	const byte *pChunkyEnd = pChunky + (height - 1) * srcPitch + width * format.bytesPerPixel;
+	const byte *pChunkyEnd = pChunky + (height - 1) * srcPitch + width;
 
-	byte *pScreen = (byte *)getPixels() + destY * pitch + destX * getBitsPerPixel()/8;
+	byte *pScreen = (byte *)getBasePtr(0, destY) + destX * getBitsPerPixel()/8;
 
 	if (getBitsPerPixel() == 8) {
 		if (srcPitch == width) {
@@ -212,15 +209,17 @@ void AtariSurface::drawMaskedSprite(
 	assert(subRect.width() % 16 == 0);
 	assert(subRect.width() == srcSurface.w);
 	assert(srcSurface.format == format);
+	assert(srcSurface.w == srcMask.w);
+	assert(srcSurface.h == srcMask.h);
 
-	if (getBitsPerPixel() == 4) {
-		asm_draw_4bpl_sprite(
+	if (getBitsPerPixel() == 8) {
+		asm_draw_8bpl_sprite(
 			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
 			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
 			destX, destY,
 			pitch, subRect.width(), subRect.height());
-	} else if (getBitsPerPixel() == 8) {
-		asm_draw_8bpl_sprite(
+	} else {
+		asm_draw_4bpl_sprite(
 			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
 			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
 			destX, destY,
diff --git a/graphics/blit/blit-atari.cpp b/graphics/blit/blit-atari.cpp
index 15e266990a7..e8cfa81a272 100644
--- a/graphics/blit/blit-atari.cpp
+++ b/graphics/blit/blit-atari.cpp
@@ -47,7 +47,7 @@ namespace Graphics {
 void keyBlitLogicAtari(byte *dst, const byte *src, const uint w, const uint h,
 					   const uint srcDelta, const uint dstDelta, const uint32 key) {
 #ifdef USE_SV_BLITTER
-	if (key == 0 && ((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
+	if (key == 0 && (uintptr)src >= 0xA0000000 && (uintptr)dst >= 0xA0000000) {
 		if (g_superVidelFwVersion >= 9) {
 			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC1
 			*SV_BLITTER_FIFO = (long)(g_blitMask ? g_blitMask : src);	// SV_BLITTER_SRC2
@@ -101,7 +101,7 @@ void copyBlit(byte *dst, const byte *src,
 		return;
 
 #ifdef USE_SV_BLITTER
-	if (((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
+	if ((uintptr)src >= 0xA0000000 && (uintptr)dst >= 0xA0000000) {
 		if (g_superVidelFwVersion >= 9) {
 			*SV_BLITTER_FIFO = (long)src;				// SV_BLITTER_SRC1
 			*SV_BLITTER_FIFO = 0x00000000;				// SV_BLITTER_SRC2


Commit: 25d125bdc0196e7516816776fe5c046a49f9fae1
    https://github.com/scummvm/scummvm/commit/25d125bdc0196e7516816776fe5c046a49f9fae1
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Avoid redefinition warning

DISABLE_FANCY_THEMES implies DISABLE_LAUNCHERDISPLAY_GRID.

Changed paths:
    backends/platform/atari/build-release.sh
    configure


diff --git a/backends/platform/atari/build-release.sh b/backends/platform/atari/build-release.sh
index 59d2484b112..2a58eeaa569 100755
--- a/backends/platform/atari/build-release.sh
+++ b/backends/platform/atari/build-release.sh
@@ -10,7 +10,8 @@ PLATFORM=m68k-atari-mintelf
 FASTCALL=false
 
 export ASFLAGS="-m68020-60"
-export CXXFLAGS="-m68020-60 -DUSE_MOVE16 -DUSE_SUPERVIDEL -DUSE_SV_BLITTER"
+export CXXFLAGS="-m68020-60 -DUSE_MOVE16 -DUSE_SUPERVIDEL -DUSE_SV_BLITTER -DDISABLE_LAUNCHERDISPLAY_GRID"
+
 export LDFLAGS="-m68020-60"
 export PKG_CONFIG_LIBDIR="$(${PLATFORM}-gcc -print-sysroot)/usr/lib/m68020-60/pkgconfig"
 
diff --git a/configure b/configure
index b41409714f7..4641381f771 100755
--- a/configure
+++ b/configure
@@ -4090,7 +4090,6 @@ case $_backend in
 		;;
 	atari)
 		define_in_config_if_yes yes "ATARI"
-		append_var DEFINES "-DDISABLE_LAUNCHERDISPLAY_GRID"
 		append_var DEFINES "-DDISABLE_NES_APU"
 		#append_var DEFINES "-DDISABLE_DOSBOX_OPL"
 		append_var LIBS "-lgem"


Commit: eb64b14b81a723b3b692f95e1179f28356594e67
    https://github.com/scummvm/scummvm/commit/eb64b14b81a723b3b692f95e1179f28356594e67
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2025-06-25T23:50:35+02:00

Commit Message:
BACKENDS: ATARI: Implement proper cursor clipping

Previous implementation had to create a new surface every time srcRect
has been changed and as a bonus, it would (harmlessly but still) do a
read-modify-write past the screen buffer.

Changed paths:
    backends/graphics/atari/atari-cursor.cpp
    backends/graphics/atari/atari-cursor.h
    backends/graphics/atari/atari-graphics-asm.S
    backends/graphics/atari/atari-graphics-asm.h
    backends/graphics/atari/atari-surface.cpp
    backends/graphics/atari/atari-surface.h


diff --git a/backends/graphics/atari/atari-cursor.cpp b/backends/graphics/atari/atari-cursor.cpp
index daee5389246..28597229fe6 100644
--- a/backends/graphics/atari/atari-cursor.cpp
+++ b/backends/graphics/atari/atari-cursor.cpp
@@ -137,12 +137,11 @@ void Cursor::updatePosition(int deltaX, int deltaY) {
 	_globalSurfaceChanged = true;
 }
 
-void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
+/* static */ void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
 	static int rShift, gShift, bShift;
 	static int rMask, gMask, bMask;
 
-	// TODO: maintain a max width
-	const int cursorWidth = g_hasSuperVidel ? _width : ((_srcRect.width() + 15) & (-16));
+	const int cursorWidth = g_hasSuperVidel ? _width : ((_width + 15) & (-16));
 	const int cursorHeight = _height;
 	const bool isCLUT8 = format.isCLUT8();
 
@@ -165,20 +164,17 @@ void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
 		_surfaceMask.w = _surface.w;
 	}
 
-	const int srcRectWidth = g_hasSuperVidel ? _width : _srcRect.width();
-
-	const byte *src = g_hasSuperVidel ? _buf : _buf + _srcRect.left;
+	const byte *src = _buf;
 	byte *dst = (byte *)_surface.getPixels();
 	byte *dstMask = (byte *)_surfaceMask.getPixels();
 	uint16 *dstMask16 = (uint16 *)_surfaceMask.getPixels();
-	const int srcPadding = _width - srcRectWidth;
-	const int dstPadding = _surface.w - srcRectWidth;
+	const int dstPadding = _surface.w - _width;
 
 	uint16 mask16 = 0xffff;
 	uint16 invertedBit = 0x7fff;
 
-	for (int j = 0; j < cursorHeight; ++j) {
-		for (int i = 0; i < srcRectWidth; ++i) {
+	for (int j = 0; j < _height; ++j) {
+		for (int i = 0; i < _width; ++i) {
 			const uint32 color = *src++;
 
 			if (color != _keycolor) {
@@ -211,8 +207,6 @@ void Cursor::convertSurfaceTo(const Graphics::PixelFormat &format) {
 			invertedBit = (invertedBit >> 1) | (invertedBit << (sizeof (invertedBit) * 8 - 1));
 		}
 
-		src += srcPadding;
-
 		if (dstPadding) {
 			assert(!g_hasSuperVidel);
 
@@ -272,13 +266,10 @@ void Cursor::saveBackground() {
 void Cursor::draw() {
 	AtariSurface &dstSurface  = *_screenSurf;
 	const int dstBitsPerPixel = dstSurface.getBitsPerPixel();
-	const int xOffset         = (dstSurface.w - _boundingSurf->w) / 2;
 
 	//atari_debug("Cursor::draw: %d %d %d %d", _dstRect.left, _dstRect.top, _dstRect.width(), _dstRect.height());
 
-	if (_globalSurfaceChanged || _srcRect.width() != _previousSrcRect.width()) {
-		_previousSrcRect = _srcRect;
-
+	if (_globalSurfaceChanged) {
 		convertSurfaceTo(dstSurface.format);
 
 		if (!g_hasSuperVidel) {
@@ -300,12 +291,9 @@ void Cursor::draw() {
 	}
 
 	dstSurface.drawMaskedSprite(
-		_surface, _surfaceMask,
-		_dstRect.left + xOffset, _dstRect.top,
-		g_hasSuperVidel
-			? _srcRect
-			// TODO: _srcRect and add clipping to AtariSurface::drawMaskedSprite
-			: Common::Rect(0, _srcRect.top, _surface.w, _srcRect.bottom));
+		_surface, _surfaceMask, *_boundingSurf,
+		_dstRect.left, _dstRect.top,
+		_srcRect);
 
 	_visibilityChanged = _positionChanged = _surfaceChanged = false;
 }
diff --git a/backends/graphics/atari/atari-cursor.h b/backends/graphics/atari/atari-cursor.h
index 4d5ed0c1d15..5daf26470af 100644
--- a/backends/graphics/atari/atari-cursor.h
+++ b/backends/graphics/atari/atari-cursor.h
@@ -43,7 +43,7 @@ struct Cursor {
 		_surfaceChanged = true;
 		_visibilityChanged = false;
 
-		_savedRect = _previousSrcRect = _alignedDstRect = Common::Rect();
+		_savedRect = _alignedDstRect = Common::Rect();
 	}
 
 	// updates outOfScreen OR srcRect/dstRect (only if visible/needed)
@@ -100,7 +100,7 @@ struct Cursor {
 	void draw();
 
 private:
-	void convertSurfaceTo(const Graphics::PixelFormat &format);
+	static void convertSurfaceTo(const Graphics::PixelFormat &format);
 	void restoreBackground();
 
 	AtariSurface *_screenSurf;
@@ -119,7 +119,6 @@ private:
 
 	Graphics::Surface _savedBackground;
 	Common::Rect _savedRect;
-	Common::Rect _previousSrcRect;
 	Common::Rect _alignedDstRect;
 
 	// related to 'surface'
diff --git a/backends/graphics/atari/atari-graphics-asm.S b/backends/graphics/atari/atari-graphics-asm.S
index 772a47d8683..72e30b27a41 100644
--- a/backends/graphics/atari/atari-graphics-asm.S
+++ b/backends/graphics/atari/atari-graphics-asm.S
@@ -26,34 +26,45 @@
 
 	.text
 
+skip_first_pix16:
+	dc.b	0
+skip_last_pix16:
+	dc.b	0
+
 | extern void asm_draw_4bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
-|				   uint destX, uint destY, uint dstPitch, uint w, uint h);
-|
+|				   uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
+|				   bool skipFirstPix16, bool skipLastPix16);
 SYM(asm_draw_4bpl_sprite):
-	movem.l	d0-d7/a0-a2,-(sp)		| 11 longs
+	movem.l	d2-d7/a2,-(sp)			| 7 longs
 
 #ifdef __FASTCALL__
 	move.l	a0,a2				| a2: dstBuffer
 						| a1: srcBuffer
-	move.l	(4+11*4,sp),a0			| a0: srcMask
+	move.l	(4+7*4,sp),a0			| a0: srcMask
 						| d0.w: destX
 						| d1.w: destY
 	move.l	d2,d3				| d3.w: dstPitch
-	ext.l	d3				| d3.l: dstPitch
-	move.l	(8+11*4,sp),d6			| d6.w: w
-	lsr.w	#4,d6				| d6.w: w/16
-	move.l	(12+11*4,sp),d7			| d7.w: h
+	move.l	(8+7*4,sp),d4			| d4.w: srcPitch
+	move.l	(12+7*4,sp),d6			| d6.w: w
+	move.l	(16+7*4,sp),d7			| d7.w: h
+	tst.l	(20+7*4,sp)			| skipFirstPix16?
+	sne	skip_first_pix16
+	tst.l	(24+7*4,sp)			| skipLastPix16?
+	sne	skip_last_pix16
 #else
-	move.l	(4+11*4,sp),a2			| a2: dstBuffer
-	move.l	(8+11*4,sp),a1			| a1: srcBuffer
-	move.l	(12+11*4,sp),a0			| a0: srcMask
-	move.l	(16+11*4,sp),d0			| d0.w: destX
-	move.l	(20+11*4,sp),d1			| d1.w: destY
-	move.l	(24+11*4,sp),d3			| d3.w: dstPitch
-	ext.l	d3				| d3.l: dstPitch
-	move.l	(28+11*4,sp),d6			| d6.w: w
-	lsr.w	#4,d6				| d6.w: w/16
-	move.l	(32+11*4,sp),d7			| d7.w: h
+	move.l	(4+7*4,sp),a2			| a2: dstBuffer
+	move.l	(8+7*4,sp),a1			| a1: srcBuffer
+	move.l	(12+7*4,sp),a0			| a0: srcMask
+	move.l	(16+7*4,sp),d0			| d0.w: destX
+	move.l	(20+7*4,sp),d1			| d1.w: destY
+	move.l	(24+7*4,sp),d3			| d3.w: dstPitch
+	move.l	(28+7*4,sp),d4			| d4.w: srcPitch
+	move.l	(32+7*4,sp),d6			| d6.w: w
+	move.l	(36+7*4,sp),d7			| d7.w: h
+	tst.l	(40+7*4,sp)			| skipFirstPix16?
+	sne	skip_first_pix16
+	tst.l	(44+7*4,sp)			| skipLastPix16?
+	sne	skip_last_pix16
 #endif
 
 | Draws a 4 bitplane sprite at any position on screen.
@@ -67,216 +78,433 @@ SYM(asm_draw_4bpl_sprite):
 |        a1: address of bitmapdata
 |        a2: screen start address
 
-	move.w  d0,d2				| / Calculate the
-	andi.w  #0b111111110000,d0		| | number of bits
-	sub.w   d0,d2				| \ to shift right.
-	lsr.w   #1,d0				| / Add x-position to
-	adda.w  d0,a2				| \ screenaddress.
-	mulu.w  d3,d1				| / Add y-position to
-	adda.l  d1,a2				| \ screenaddress.
-	move.w  d6,d1				| / Prepare
-	lsl.w   #3,d1				| | offset
-	move.l  d3,d4				| | to next
-	sub.w   d1,d4				| \ screenline.
-	subq.w  #1,d7				| Adjust for dbra.
-	subq.w  #1,d6				| Adjust for dbra.
-	move.w  d6,d5				| Backup xloopcount in d5.w.
-	moveq   #16,d1				| Size of two chunks.
-
+	move.w	d0,d2				| / Calculate the
+	andi.w	#0b111111110000,d0		| | number of bits
+	sub.w	d0,d2				| \ to shift right.
+	lsr.w	#1,d0				| / Add x-position to
+	adda.w	d0,a2				| \ screenaddress.
+	mulu.w	d3,d1				| / Add y-position to
+	adda.l	d1,a2				| \ screenaddress.
+	lsr.w	#1,d6
+	sub.w	d6,d3				| / Prepare offset to next
+	ext.l	d3				| \ destination line.
+	sub.w	d6,d4				| / Prepare offset to next
+	ext.l	d4				| \ source line.
+	subq.w	#1,d7				| Adjust for dbra.
+	lsr.w	#3,d6				| d6.w: w/16
+	subq.w	#1,d6				| Adjust for dbra.
+	move.w	d6,d5				| Backup xloopcount in d5.w.
+
+	tst.b	(skip_first_pix16,pc)
+	jeq	1f
+	subq.w	#1,d5
+1:
+	tst.b	(skip_last_pix16,pc)
+	jeq	2f
+	subq.w	#1,d5
+2:
 sprite4_yloop:
-	move.w  d5,d6				| Restore xloop counter.
+	move.w	d5,d6				| Restore xloop counter.
+
+	tst.b	(skip_first_pix16,pc)
+	jeq	1f
+
+	moveq	#16,d1
+	sub.w	d2,d1
+
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	rol.l	d1,d0				| Shift it!
+	addq.l	#8,a2
+	and.w	d0,(a2)+			| Mask overspill bitplane 0.
+	and.w	d0,(a2)+			| Mask overspill bitplane 1.
+	and.w	d0,(a2)+			| Mask overspill bitplane 2.
+	and.w	d0,(a2)+			| Mask overspill bitplane 3.
+	subq.l	#8,a2				| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 3.
+
+	subq.l	#8,a2
+
+1:	tst.w	d6
+	jmi	sprite4_xloop_done
 
 sprite4_xloop:
-	moveq   #0xffffffff,d0			| Prepare for maskshifting.
-	move.w  (a0)+,d0			| Get 16pixel mask in d0.w.
-	ror.l   d2,d0				| Shift it!
-	and.w   d0,(a2)+			| Mask bitplane 0.
-	and.w   d0,(a2)+			| Mask bitplane 1.
-	and.w   d0,(a2)+			| Mask bitplane 2.
-	and.w   d0,(a2)+			| Mask bitplane 3.
-	swap    d0				| Get overspill in loword.
-	and.w   d0,(a2)+			| Mask overspill bitplane 0.
-	and.w   d0,(a2)+			| Mask overspill bitplane 1.
-	and.w   d0,(a2)+			| Mask overspill bitplane 2.
-	and.w   d0,(a2)+			| Mask overspill bitplane 3.
-	suba.l  d1,a2				| Return to blockstart.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 0.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,6(a2)			| Paint overspill bitplane 0.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 1.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,6(a2)			| Paint overspill bitplane 1.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 2.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,6(a2)			| Paint overspill bitplane 2.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 3.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,6(a2)			| Paint overspill bitplane 3.
-
-	dbra    d6,sprite4_xloop		| Loop until blocks done.
-
-	adda.l  d4,a2				| Goto next screenline.
-	dbra    d7,sprite4_yloop		| Loop until lines done.
-
-	movem.l	(sp)+,d0-d7/a0-a2
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	ror.l	d2,d0				| Shift it!
+	and.w	d0,(a2)+			| Mask bitplane 0.
+	and.w	d0,(a2)+			| Mask bitplane 1.
+	and.w	d0,(a2)+			| Mask bitplane 2.
+	and.w	d0,(a2)+			| Mask bitplane 3.
+	swap	d0				| Get overspill in loword.
+	and.w	d0,(a2)+			| Mask overspill bitplane 0.
+	and.w	d0,(a2)+			| Mask overspill bitplane 1.
+	and.w	d0,(a2)+			| Mask overspill bitplane 2.
+	and.w	d0,(a2)+			| Mask overspill bitplane 3.
+	lea	(-16,a2),a2			| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 0.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,6(a2)			| Paint overspill bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 1.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,6(a2)			| Paint overspill bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 2.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,6(a2)			| Paint overspill bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 3.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,6(a2)			| Paint overspill bitplane 3.
+
+	dbra	d6,sprite4_xloop		| Loop until blocks done.
+
+sprite4_xloop_done:
+	tst.b	(skip_last_pix16,pc)
+	jeq	1f
+
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	ror.l	d2,d0				| Shift it!
+	and.w	d0,(a2)+			| Mask bitplane 0.
+	and.w	d0,(a2)+			| Mask bitplane 1.
+	and.w	d0,(a2)+			| Mask bitplane 2.
+	and.w	d0,(a2)+			| Mask bitplane 3.
+	subq.l	#8,a2				| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 3.
+
+1:	move.l	d4,d0
+	asr.l	#2,d0
+	adda.l	d0,a0
+	adda.l	d4,a1
+	adda.l	d3,a2				| Goto next screenline.
+	dbra	d7,sprite4_yloop		| Loop until lines done.
+
+	movem.l	(sp)+,d2-d7/a2
 	rts
 
 | extern void asm_draw_8bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
-|				   uint destX, uint destY, uint dstPitch, uint w, uint h);
-|
+|				   uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
+|				   bool skipFirstPix16, bool skipLastPix16);
 SYM(asm_draw_8bpl_sprite):
-	movem.l	d0-d7/a0-a2,-(sp)		| 11 longs
+	movem.l	d2-d7/a2,-(sp)			| 7 longs
 
 #ifdef __FASTCALL__
 	move.l	a0,a2				| a2: dstBuffer
 						| a1: srcBuffer
-	move.l	(4+11*4,sp),a0			| a0: srcMask
+	move.l	(4+7*4,sp),a0			| a0: srcMask
 						| d0.w: destX
 						| d1.w: destY
 	move.l	d2,d3				| d3.w: dstPitch
-	ext.l	d3				| d3.l: dstPitch
-	move.l	(8+11*4,sp),d6			| d6.w: w
-	lsr.w	#4,d6				| d6.w: w/16
-	move.l	(12+11*4,sp),d7			| d7.w: h
+	move.l	(8+7*4,sp),d4			| d4.w: srcPitch
+	move.l	(12+7*4,sp),d6			| d6.w: w
+	move.l	(16+7*4,sp),d7			| d7.w: h
+	tst.l	(20+7*4,sp)			| skipFirstPix16?
+	sne	skip_first_pix16
+	tst.l	(24+7*4,sp)			| skipLastPix16?
+	sne	skip_last_pix16
 #else
-	move.l	(4+11*4,sp),a2			| a2: dstBuffer
-	move.l	(8+11*4,sp),a1			| a1: srcBuffer
-	move.l	(12+11*4,sp),a0			| a0: srcMask
-	move.l	(16+11*4,sp),d0			| d0.w: destX
-	move.l	(20+11*4,sp),d1			| d1.w: destY
-	move.l	(24+11*4,sp),d3			| d3.w: dstPitch
-	ext.l	d3				| d3.l: dstPitch
-	move.l	(28+11*4,sp),d6			| d6.w: w
-	lsr.w	#4,d6				| d6.w: w/16
-	move.l	(32+11*4,sp),d7			| d7.w: h
+	move.l	(4+7*4,sp),a2			| a2: dstBuffer
+	move.l	(8+7*4,sp),a1			| a1: srcBuffer
+	move.l	(12+7*4,sp),a0			| a0: srcMask
+	move.l	(16+7*4,sp),d0			| d0.w: destX
+	move.l	(20+7*4,sp),d1			| d1.w: destY
+	move.l	(24+7*4,sp),d3			| d3.w: dstPitch
+	move.l	(28+7*4,sp),d4			| d4.w: srcPitch
+	move.l	(32+7*4,sp),d6			| d6.w: w
+	move.l	(36+7*4,sp),d7			| d7.w: h
+	tst.l	(40+7*4,sp)			| skipFirstPix16?
+	sne	skip_first_pix16
+	tst.l	(45+7*4,sp)			| skipLastPix16?
+	sne	skip_last_pix16
 #endif
-
-	move.w  d0,d2				| / Calculate the
-	andi.w  #0b111111110000,d0		| | number of bits
-	sub.w   d0,d2				| \ to shift right.
-	adda.w  d0,a2				| Add x-position to screenaddress.
-	mulu.w  d3,d1				| / Add y-position to
-	adda.l  d1,a2				| \ screenaddress.
-	move.w  d6,d1				| / Prepare
-	lsl.w   #4,d1				| | offset
-	move.l  d3,d4				| | to next
-	sub.w   d1,d4				| \ screenline.
-	subq.w  #1,d7				| Adjust for dbra.
-	subq.w  #1,d6				| Adjust for dbra.
-	move.w  d6,d5				| Backup xloopcount in d5.w.
-	moveq   #32,d1				| Size of two chunks.
-
+	move.w	d0,d2				| / Calculate the
+	andi.w	#0b111111110000,d0		| | number of bits
+	sub.w	d0,d2				| \ to shift right.
+	adda.w	d0,a2				| Add x-position to screenaddress.
+	mulu.w	d3,d1				| / Add y-position to
+	adda.l	d1,a2				| \ screenaddress.
+	sub.w	d6,d3				| / Prepare offset to next
+	ext.l	d3				| \ destination line.
+	sub.w	d6,d4				| / Prepare offset to next
+	ext.l	d4				| \ source line.
+	subq.w	#1,d7				| Adjust for dbra.
+	lsr.w	#4,d6				| d6.w: w/16
+	subq.w	#1,d6				| Adjust for dbra.
+	move.w	d6,d5				| Backup xloopcount in d5.w.
+
+	tst.b	(skip_first_pix16,pc)
+	jeq	1f
+	subq.w	#1,d5
+1:
+	tst.b	(skip_last_pix16,pc)
+	jeq	2f
+	subq.w	#1,d5
+2:
 sprite8_yloop:
-	move.w  d5,d6				| Restore xloop counter.
+	move.w	d5,d6				| Restore xloop counter.
+
+	tst.b	(skip_first_pix16,pc)
+	jeq	1f
+
+	moveq	#16,d1
+	sub.w	d2,d1
+
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	rol.l	d1,d0				| Shift it!
+	lea	(16,a2),a2
+	and.w	d0,(a2)+			| Mask overspill bitplane 0.
+	and.w	d0,(a2)+			| Mask overspill bitplane 1.
+	and.w	d0,(a2)+			| Mask overspill bitplane 2.
+	and.w	d0,(a2)+			| Mask overspill bitplane 3.
+	and.w	d0,(a2)+			| Mask overspill bitplane 4.
+	and.w	d0,(a2)+			| Mask overspill bitplane 5.
+	and.w	d0,(a2)+			| Mask overspill bitplane 6.
+	and.w	d0,(a2)+			| Mask overspill bitplane 7.
+	lea	(-16,a2),a2			| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 3.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 4.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 5.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 6.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	rol.l	d1,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint overspill bitplane 7.
+
+	lea	(-16,a2),a2
+
+1:	tst.w	d6
+	jmi	sprite8_xloop_done
 
 sprite8_xloop:
-	moveq   #0xffffffff,d0			| Prepare for maskshifting.
-	move.w  (a0)+,d0			| Get 16pixel mask in d0.w.
-	ror.l   d2,d0				| Shift it!
-	and.w   d0,(a2)+			| Mask bitplane 0.
-	and.w   d0,(a2)+			| Mask bitplane 1.
-	and.w   d0,(a2)+			| Mask bitplane 2.
-	and.w   d0,(a2)+			| Mask bitplane 3.
-	and.w   d0,(a2)+			| Mask bitplane 4.
-	and.w   d0,(a2)+			| Mask bitplane 5.
-	and.w   d0,(a2)+			| Mask bitplane 6.
-	and.w   d0,(a2)+			| Mask bitplane 7.
-	swap    d0				| Get overspill in loword.
-	and.w   d0,(a2)+			| Mask overspill bitplane 0.
-	and.w   d0,(a2)+			| Mask overspill bitplane 1.
-	and.w   d0,(a2)+			| Mask overspill bitplane 2.
-	and.w   d0,(a2)+			| Mask overspill bitplane 3.
-	and.w   d0,(a2)+			| Mask overspill bitplane 4.
-	and.w   d0,(a2)+			| Mask overspill bitplane 5.
-	and.w   d0,(a2)+			| Mask overspill bitplane 6.
-	and.w   d0,(a2)+			| Mask overspill bitplane 7.
-	suba.l  d1,a2				| Return to blockstart.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 0.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 0.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 1.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 1.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 2.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 2.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 3.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 3.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 4.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 4.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 5.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 5.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 6.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 6.
-
-	moveq   #0,d0				| Prepare for bitmapshifting.
-	move.w  (a1)+,d0			| Get bitplaneword in d0.w.
-	ror.l   d2,d0				| Shift it.
-	or.w    d0,(a2)+			| Paint bitplane 7.
-	swap    d0				| Get overspill in loword.
-	or.w    d0,14(a2)			| Paint overspill bitplane 7.
-
-	dbra    d6,sprite8_xloop		| Loop until blocks done.
-
-	adda.l  d4,a2				| Goto next screenline.
-	dbra    d7,sprite8_yloop		| Loop until lines done.
-
-	movem.l	(sp)+,d0-d7/a0-a2
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	ror.l	d2,d0				| Shift it!
+	and.w	d0,(a2)+			| Mask bitplane 0.
+	and.w	d0,(a2)+			| Mask bitplane 1.
+	and.w	d0,(a2)+			| Mask bitplane 2.
+	and.w	d0,(a2)+			| Mask bitplane 3.
+	and.w	d0,(a2)+			| Mask bitplane 4.
+	and.w	d0,(a2)+			| Mask bitplane 5.
+	and.w	d0,(a2)+			| Mask bitplane 6.
+	and.w	d0,(a2)+			| Mask bitplane 7.
+	swap	d0				| Get overspill in loword.
+	and.w	d0,(a2)+			| Mask overspill bitplane 0.
+	and.w	d0,(a2)+			| Mask overspill bitplane 1.
+	and.w	d0,(a2)+			| Mask overspill bitplane 2.
+	and.w	d0,(a2)+			| Mask overspill bitplane 3.
+	and.w	d0,(a2)+			| Mask overspill bitplane 4.
+	and.w	d0,(a2)+			| Mask overspill bitplane 5.
+	and.w	d0,(a2)+			| Mask overspill bitplane 6.
+	and.w	d0,(a2)+			| Mask overspill bitplane 7.
+	lea	(-32,a2),a2			| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 0.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 1.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 2.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 3.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 3.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 4.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 4.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 5.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 5.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 6.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 6.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 7.
+	swap	d0				| Get overspill in loword.
+	or.w	d0,14(a2)			| Paint overspill bitplane 7.
+
+	dbra	d6,sprite8_xloop		| Loop until blocks done.
+
+sprite8_xloop_done:
+	tst.b	(skip_last_pix16,pc)
+	jeq	1f
+
+	moveq	#0xffffffff,d0			| Prepare for maskshifting.
+	move.w	(a0)+,d0			| Get 16pixel mask in d0.w.
+	ror.l	d2,d0				| Shift it!
+	and.w	d0,(a2)+			| Mask bitplane 0.
+	and.w	d0,(a2)+			| Mask bitplane 1.
+	and.w	d0,(a2)+			| Mask bitplane 2.
+	and.w	d0,(a2)+			| Mask bitplane 3.
+	and.w	d0,(a2)+			| Mask bitplane 4.
+	and.w	d0,(a2)+			| Mask bitplane 5.
+	and.w	d0,(a2)+			| Mask bitplane 6.
+	and.w	d0,(a2)+			| Mask bitplane 7.
+	lea	(-16,a2),a2			| Return to blockstart.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 0.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 1.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 2.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 3.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 4.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 5.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 6.
+
+	moveq	#0,d0				| Prepare for bitmapshifting.
+	move.w	(a1)+,d0			| Get bitplaneword in d0.w.
+	ror.l	d2,d0				| Shift it.
+	or.w	d0,(a2)+			| Paint bitplane 7.
+
+1:	move.l	d4,d0
+	asr.l	#3,d0
+	adda.l	d0,a0
+	adda.l	d4,a1
+	adda.l	d3,a2				| Goto next screenline.
+	dbra	d7,sprite8_yloop		| Loop until lines done.
+
+	movem.l	(sp)+,d2-d7/a2
 	rts
-
-
-	.bss
-	.even
-
-save_pal:
-	ds.l	256+16/2			| old colours (sized for falcon+ste palette)
-save_video:
-	ds.b	32+12+2				| old video regs (size of falcon regs)
diff --git a/backends/graphics/atari/atari-graphics-asm.h b/backends/graphics/atari/atari-graphics-asm.h
index 51a8bd40900..949575e7d43 100644
--- a/backends/graphics/atari/atari-graphics-asm.h
+++ b/backends/graphics/atari/atari-graphics-asm.h
@@ -35,11 +35,15 @@ extern "C" {
  * @param destX sprite's X position (in pixels)
  * @param destY sprite's Y position (in pixels)
  * @param dstPitch destination buffer's pitch (in bytes)
+ * @param srcPitch source buffer's pitch (in bytes)
  * @param w sprite's width (in pixels)
  * @param h sprite's height (in pixels)
+ * @param skipFirstPix16 do not write first 16 pixels
+ * @param skipLastPix16 do not write last 16 pixels
  */
 void asm_draw_4bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
-						  uint destX, uint destY, uint dstPitch, uint w, uint h);
+						  uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
+						  bool skipFirstPix16, bool skipLastPix16);
 /**
  * Copy 8bpl sprite into 8bpl buffer. Sprite's width must be multiply of 16.
  *
@@ -49,11 +53,15 @@ void asm_draw_4bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint
  * @param destX sprite's X position (in pixels)
  * @param destY sprite's Y position (in pixels)
  * @param dstPitch destination buffer's pitch (in bytes)
+ * @param srcPitch source buffer's pitch (in bytes)
  * @param w sprite's width (in pixels)
  * @param h sprite's height (in pixels)
+ * @param skipFirstPix16 do not write first 16 pixels
+ * @param skipLastPix16 do not write last 16 pixels
  */
 void asm_draw_8bpl_sprite(uint16 *dstBuffer, const uint16 *srcBuffer, const uint16 *srcMask,
-						  uint destX, uint destY, uint dstPitch, uint w, uint h);
+						  uint destX, uint destY, uint dstPitch, uint srcPitch, uint w, uint h,
+						  bool skipFirstPix16, bool skipLastPix16);
 
 }
 
diff --git a/backends/graphics/atari/atari-surface.cpp b/backends/graphics/atari/atari-surface.cpp
index 992293815db..14997e1b1cf 100644
--- a/backends/graphics/atari/atari-surface.cpp
+++ b/backends/graphics/atari/atari-surface.cpp
@@ -204,26 +204,59 @@ void AtariSurface::copyRectToSurface(const void *buffer, int srcPitch, int destX
 
 void AtariSurface::drawMaskedSprite(
 	const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+	const Graphics::Surface &boundingSurface,
 	int destX, int destY,
 	const Common::Rect &subRect) {
-	assert(subRect.width() % 16 == 0);
-	assert(subRect.width() == srcSurface.w);
 	assert(srcSurface.format == format);
 	assert(srcSurface.w == srcMask.w);
 	assert(srcSurface.h == srcMask.h);
 
+	bool skipFirstPix16 = false;
+	bool skipLastPix16  = false;
+
+	int srcSurfaceLeft  = 0;
+	int srcSurfaceWidth = srcSurface.w;
+	int dstSurfaceLeft  = 0;
+
+	if (subRect.left > 0) {
+		skipFirstPix16   = true;
+
+		const int offset = subRect.left & (-16);
+		srcSurfaceLeft  += offset;
+		srcSurfaceWidth -= offset;
+
+		destX            = 16 - (subRect.left & (16-1));
+		dstSurfaceLeft  -= 16;
+	}
+
+	if (destX + srcSurfaceWidth > boundingSurface.w) {
+		skipLastPix16    = true;
+
+		const int offset = (destX + srcSurfaceWidth - boundingSurface.w) & (-16);
+		srcSurfaceWidth -= offset;
+	}
+
+	assert(srcSurfaceLeft % 16 == 0);
+	assert(srcSurfaceWidth % 16 == 0);
+
+	destX += (this->w - boundingSurface.w) / 2;
+
 	if (getBitsPerPixel() == 8) {
 		asm_draw_8bpl_sprite(
-			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
-			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
+			(uint16 *)getBasePtr(dstSurfaceLeft, 0),
+			(const uint16 *)srcSurface.getBasePtr(srcSurfaceLeft, subRect.top),
+			(const uint16 *)srcMask.getBasePtr(srcSurfaceLeft / 8, subRect.top),
 			destX, destY,
-			pitch, subRect.width(), subRect.height());
+			pitch, srcSurface.w, srcSurfaceWidth, subRect.height(),
+			skipFirstPix16, skipLastPix16);
 	} else {
 		asm_draw_4bpl_sprite(
-			(uint16 *)getPixels(), (const uint16 *)srcSurface.getBasePtr(subRect.left, subRect.top),
-			(const uint16 *)srcMask.getBasePtr(subRect.left, subRect.top),
+			(uint16 *)getBasePtr(dstSurfaceLeft / 2, 0),
+			(const uint16 *)srcSurface.getBasePtr(srcSurfaceLeft / 2, subRect.top),
+			(const uint16 *)srcMask.getBasePtr(srcSurfaceLeft / 8, subRect.top),
 			destX, destY,
-			pitch, subRect.width(), subRect.height());
+			pitch, srcSurface.w / 2, srcSurfaceWidth, subRect.height(),
+			skipFirstPix16, skipLastPix16);
 	}
 }
 
diff --git a/backends/graphics/atari/atari-surface.h b/backends/graphics/atari/atari-surface.h
index 7bd5df84541..10d7e766d04 100644
--- a/backends/graphics/atari/atari-surface.h
+++ b/backends/graphics/atari/atari-surface.h
@@ -55,6 +55,7 @@ public:
 	}
 
 	virtual void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+								  const Graphics::Surface &boundingSurface,
 								  int destX, int destY,
 								  const Common::Rect &subRect);
 
@@ -93,6 +94,7 @@ public:
 	}
 
 	void drawMaskedSprite(const Graphics::Surface &srcSurface, const Graphics::Surface &srcMask,
+						  const Graphics::Surface &boundingSurface,
 						  int destX, int destY,
 						  const Common::Rect &subRect) override {
 #ifdef USE_SV_BLITTER




More information about the Scummvm-git-logs mailing list