[Scummvm-git-logs] scummvm master -> d9eee7906ab544ad15fc8d4c5f68c80a0c7e7f71
mikrosk
noreply at scummvm.org
Thu Jun 15 21:37:08 UTC 2023
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
5537759c53 BACKENDS: ATARI: Rework
2ce02658ec BACKENDS: ATARI: DMA playback is not always active
d9eee7906a BACKENDS: ATARI: Use unordered_set for dirty rects
Commit: 5537759c5355b45a6c208bd1d43ac1700aaea543
https://github.com/scummvm/scummvm/commit/5537759c5355b45a6c208bd1d43ac1700aaea543
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-06-15T22:57:55+02:00
Commit Message:
BACKENDS: ATARI: Rework
- Atari TT support
- all video and audio is now handled via XBIOS
- reworked IKBD handling using Kbdvbase vectors, esp. Kbdvec()
- video uses proper triple buffer
- arbitrary game screen size support
- many fixes and optimizations
Changed paths:
R backends/graphics/atari/videl-resolutions.cpp
R backends/graphics/atari/videl-resolutions.h
backends/graphics/atari/atari-graphics-asm.S
backends/graphics/atari/atari-graphics-asm.h
backends/graphics/atari/atari-graphics-superblitter.h
backends/graphics/atari/atari-graphics-supervidel.h
backends/graphics/atari/atari-graphics-videl.h
backends/graphics/atari/atari-graphics.cpp
backends/graphics/atari/atari-graphics.h
backends/graphics/atari/atari_c2p-asm.S
backends/graphics/atari/atari_c2p-asm.h
backends/mixer/atari/atari-mixer.cpp
backends/mixer/atari/atari-mixer.h
backends/module.mk
backends/platform/atari/atari_ikbd.S
backends/platform/atari/build-release.sh
backends/platform/atari/build-release030.sh
backends/platform/atari/osystem_atari.cpp
backends/platform/atari/osystem_atari.h
backends/platform/atari/readme.txt
configure
graphics/blit-atari.cpp
diff --git a/backends/graphics/atari/atari-graphics-asm.S b/backends/graphics/atari/atari-graphics-asm.S
index 5d79334cec2..733aadcdbb8 100644
--- a/backends/graphics/atari/atari-graphics-asm.S
+++ b/backends/graphics/atari/atari-graphics-asm.S
@@ -19,17 +19,11 @@
*
*/
- .globl _asm_screen_tt_save
- .globl _asm_screen_falcon_save
+ .global _asm_screen_tt_save
+ .global _asm_screen_falcon_save
- .globl _asm_screen_tt_restore
- .globl _asm_screen_falcon_restore
-
- .globl _asm_screen_set_tt_palette
- .globl _asm_screen_set_falcon_palette
-
- .globl _asm_screen_set_vram
- .globl _asm_screen_set_scp_res
+ .global _asm_screen_tt_restore
+ .global _asm_screen_falcon_restore
.text
@@ -97,15 +91,6 @@ falcon_save_loop:
move.w 0xffff8266.w,(a0)+ | f_s
move.w 0xffff8260.w,(a0)+ | st_s
- | install custom VBL handler
- move sr,-(sp)
- or #0x700,sr
-
- move.l 0x70.w,old_vbl
- move.l #vbl,0x70.w
-
- move (sp)+,sr
-
movem.l (sp)+,d2-d7/a2
rts
@@ -132,14 +117,6 @@ _asm_screen_tt_restore:
_asm_screen_falcon_restore:
movem.l d2-d7/a2,-(sp)
- | uninstall custom VBL handler
- move sr,-(sp)
- or #0x700,sr
-
- move.l old_vbl,0x70.w
-
- move (sp)+,sr
-
bsr wait_vbl | avoid flickering
lea save_video,a0
@@ -199,152 +176,16 @@ falcon_restore_loop:
movem.l (sp)+,d2-d7/a2
rts
-| extern void asm_screen_set_tt_palette(const uint16 pPalette[256]);
-|
-_asm_screen_set_tt_palette:
- move.l (4,sp),a0
- lea 0xffff8400.w,a1
- moveq #256/2-1,d0
-
-set_tt_palette_loop:
- move.l (a0)+,(a1)+
- dbra d0,set_tt_palette_loop
- rts
-
-| extern void asm_screen_set_falcon_palette(const byte pPalette[256*3]);
-|
-_asm_screen_set_falcon_palette:
- move.l (4,sp),a0
- lea pending_palette,a1
- move.w #256-1,d0
-
-set_falcon_palette_loop:
- clr.l d1
- move.w (a0)+,d1
- swap d1
- move.b (a0)+,d1
- move.l d1,(a1)+
- dbra d0,set_falcon_palette_loop
-
- addq.w #1,has_pending_palette
- rts
-
-| extern void asm_screen_set_vram(const void* pScreen);
-|
-_asm_screen_set_vram:
- move.l (4,sp),pending_vram
-
- addq.w #1,has_pending_vram
- rts
-
-| void asm_screen_set_scp_res(const void* pScp);
-|
-_asm_screen_set_scp_res:
- move.l (4,sp),a0
- lea (122,a0),a0
- lea pending_scp,a1
- moveq #(158-122)/4-1,d0
-set_scp_res_loop:
- move.l (a0)+,(a1)+
- dbra d0,set_scp_res_loop
-
- addq.w #1,has_pending_scp
- rts
-
wait_vbl:
move.w #0x25,-(sp) | Vsync()
trap #14 |
addq.l #2,sp |
rts
- .ascii "XBRA"
- .ascii "SCUM"
-old_vbl:
- dc.l 0
-vbl:
- movem.l d0-d1/a0-a1,-(sp)
-
- addq.l #1,0x0462.w | _vbclock
- addq.l #1,0x0466.w | _frclock
-
- tst.w has_pending_scp
- beq.b vbl_no_pending_scp
-
- lea pending_scp,a0
- move.l (a0)+,0xffff8282.w
- move.l (a0)+,0xffff8286.w
- move.l (a0)+,0xffff828a.w
- move.l (a0)+,0xffff82a2.w
- move.l (a0)+,0xffff82a6.w
- move.l (a0)+,0xffff82aa.w
- move.w (a0)+,0xffff820a.w
- move.w (a0)+,0xffff82c0.w
- clr.w 0xffff8266.w
- tst.w (a0)+
- bne.b vbl_st
-
-vbl_falcon:
- move.w (a0)+,0xffff8266.w
- bra.b vbl_skip
-
-vbl_st: addq.l #1,a0
- move.b (a0)+,0xffff8260.w
-
-vbl_skip:
- move.w (a0)+,0xffff82c2.w
- move.w (a0)+,0xffff8210.w
-
- clr.w has_pending_scp
-vbl_no_pending_scp:
-
- tst.w has_pending_vram
- beq.b vbl_no_pending_vram
-
- move.l pending_vram,d0
- move.l d0,d1
- lsr.w #8,d0
- move.l d0,0xffff8200.w
- move.b d1,0xffff820d.w
-
- clr.w has_pending_vram
-vbl_no_pending_vram:
-
- tst.w has_pending_palette
- beq.b vbl_no_pending_palette
-
- lea pending_palette,a0
- lea 0xffff9800.w,a1
- moveq #256/2-1,d0
-
-vbl_falcon_palette_loop:
- move.l (a0)+,(a1)+
- move.l (a0)+,(a1)+
- dbra d0,vbl_falcon_palette_loop
-
- clr.w has_pending_palette
-
-vbl_no_pending_palette:
- movem.l (sp)+,d0-d1/a0-a1
- rte
-
.bss
.even
-has_pending_scp:
- ds.w 1
-has_pending_vram:
- ds.w 1
-has_pending_palette:
- ds.w 1
-
-pending_scp:
- ds.b 158-122 | pending SCP resolution data
-pending_vram:
- ds.l 1 | pending vram pointer
-pending_palette:
- ds.l 256 | pending palette
-
save_pal:
ds.l 256+16/2 | old colours (sized for falcon+ste palette)
save_video:
diff --git a/backends/graphics/atari/atari-graphics-asm.h b/backends/graphics/atari/atari-graphics-asm.h
index 0bdd48e6be8..93fce38f414 100644
--- a/backends/graphics/atari/atari-graphics-asm.h
+++ b/backends/graphics/atari/atari-graphics-asm.h
@@ -44,27 +44,6 @@ void asm_screen_tt_restore(void);
*/
void asm_screen_falcon_restore(void);
-/**
- * Set Atari TT palette.
- * @param pPalette 256 palette entries (0000 RRRR GGGG BBBB)
- */
-void asm_screen_set_tt_palette(const uint16 pPalette[256]);
-/**
- * Set Atari Falcon palette.
- * @param pPalette 256 palette entries (RRRRRRRR GGGGGGGG BBBBBBBB)
- */
-void asm_screen_set_falcon_palette(const byte pPalette[256*3]);
-
-/**
- * Set Atari TT/Falcon video base.
- */
-void asm_screen_set_vram(const void* pScreen);
-
-/**
- * Set Atari Falcon Videl resolution (Screenspain's SCP format).
- */
-void asm_screen_set_scp_res(const void* pScp);
-
}
#endif
diff --git a/backends/graphics/atari/atari-graphics-superblitter.h b/backends/graphics/atari/atari-graphics-superblitter.h
index 14e771f1423..c92559965e0 100644
--- a/backends/graphics/atari/atari-graphics-superblitter.h
+++ b/backends/graphics/atari/atari-graphics-superblitter.h
@@ -31,7 +31,8 @@
#define SV_VERSION ((volatile long*)0x8001007C)
inline static bool hasSuperVidel() {
- static bool hasSuperVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
+ // this works also on the TT
+ static bool hasSuperVidel = Getcookie(C_SupV, NULL) == C_FOUND && VgetMonitor() == MON_VGA;
return hasSuperVidel;
}
diff --git a/backends/graphics/atari/atari-graphics-supervidel.h b/backends/graphics/atari/atari-graphics-supervidel.h
index a8607cd12f5..25bcc01a179 100644
--- a/backends/graphics/atari/atari-graphics-supervidel.h
+++ b/backends/graphics/atari/atari-graphics-supervidel.h
@@ -29,7 +29,6 @@
#include <mint/osbind.h>
#include "backends/graphics/atari/atari-graphics-superblitter.h"
-#include "backends/graphics/atari/videl-resolutions.h"
#include "common/debug.h" // error() & warning()
#include "common/scummsys.h"
@@ -47,12 +46,6 @@ public:
else
warning("SV_XBIOS has the pmmu boost disabled, set 'pmmu_boost = true' in C:\\SV.INF");
- // patch SPSHIFT for SuperVidel's BPS8C
- for (byte *p : {scp_320x200x8_vga, scp_320x240x8_vga, scp_640x400x8_vga, scp_640x480x8_vga}) {
- uint16 *p16 = (uint16*)(p + 122 + 30);
- *p16 |= 0x1000;
- }
-
// using virtual methods so must be done here
allocateSurfaces();
}
diff --git a/backends/graphics/atari/atari-graphics-videl.h b/backends/graphics/atari/atari-graphics-videl.h
index c9906c33568..72832d8746a 100644
--- a/backends/graphics/atari/atari-graphics-videl.h
+++ b/backends/graphics/atari/atari-graphics-videl.h
@@ -71,25 +71,50 @@ private:
// 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
- if (subRect.width() == dstSurface.w) {
- asm_c2p1x1_8(
- (const byte*)srcSurface.getBasePtr(subRect.left, subRect.top),
- (const byte*)srcSurface.getBasePtr(subRect.right, subRect.bottom-1),
- (byte*)dstSurface.getBasePtr(destX, destY));
- } else {
+ const byte *pChunky = (const byte *)srcSurface.getBasePtr(subRect.left, subRect.top);
+ const byte *pChunkyEnd = (const byte *)srcSurface.getBasePtr(subRect.right, subRect.bottom-1);
+
+ const uint32 bitsPerPixel = dstSurface.format.isCLUT8() || dstSurface.format == PIXELFORMAT_RGB332 ? 8 : 4;
+ const uint32 screenPitch = dstSurface.pitch * bitsPerPixel/8;
+
+ byte *pScreen = (byte *)dstSurface.getPixels() + destY * screenPitch + 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, screenPitch);
+ return;
+ }
+ }
+
asm_c2p1x1_8_rect(
- (const byte*)srcSurface.getBasePtr(subRect.left, subRect.top),
- (const byte*)srcSurface.getBasePtr(subRect.right, subRect.bottom-1),
+ pChunky, pChunkyEnd,
+ subRect.width(),
+ srcSurface.pitch,
+ pScreen,
+ screenPitch);
+ } else {
+ // compare unmodified dst pitch
+ if (srcSurface.pitch == subRect.width() && srcSurface.pitch == dstSurface.pitch) {
+ asm_c2p1x1_4(pChunky, pChunkyEnd, pScreen);
+ return;
+ }
+
+ asm_c2p1x1_4_rect(
+ pChunky, pChunkyEnd,
subRect.width(),
srcSurface.pitch,
- (byte*)dstSurface.getBasePtr(destX, destY),
- dstSurface.pitch);
+ pScreen,
+ screenPitch);
}
}
- void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &bgSurface,
- const Graphics::Surface &srcSurface, int destX, int destY,
- const Common::Rect &subRect, uint32 key, const byte srcPalette[256*3]) const override {
+ void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
+ int destX, int destY, const Common::Rect &subRect, uint32 key,
+ const Graphics::Surface &bgSurface, const byte srcPalette[256*3]) const override {
Common::Rect backgroundRect(destX, destY, destX + subRect.width(), destY + subRect.height());
// ensure that background's left and right lie on a 16px boundary and double the width if needed
@@ -116,34 +141,7 @@ private:
cachedSurface.copyRectToSurface(bgSurface, 0, 0, backgroundRect);
// copy cursor
- if (cachedSurface.format == PIXELFORMAT_RGB332) {
- assert(srcSurface.format == PIXELFORMAT_CLUT8);
-
- // Convert CLUT8 to RGB332 palette and do copyRectToSurfaceWithKey() at the same time
- const byte *src = (const byte*)srcSurface.getBasePtr(subRect.left, subRect.top);
- byte *dst = (byte*)cachedSurface.getBasePtr(deltaX, 0);
-
- const int16 w = subRect.width();
- const int16 h = subRect.height();
-
- for (int16 y = 0; y < h; ++y) {
- for (int16 x = 0; x < w; ++x) {
- const uint32 color = *src++;
- if (color != key) {
- *dst++ = (srcPalette[color*3 + 0] & 0xe0)
- | ((srcPalette[color*3 + 1] >> 3) & 0x1c)
- | ((srcPalette[color*3 + 2] >> 6) & 0x03);
- } else {
- dst++;
- }
- }
-
- src += (srcSurface.pitch - w);
- dst += (cachedSurface.pitch - w);
- }
- } else {
- cachedSurface.copyRectToSurfaceWithKey(srcSurface, deltaX, 0, subRect, key);
- }
+ convertRectToSurfaceWithKey(cachedSurface, srcSurface, deltaX, 0, subRect, key, srcPalette);
copyRectToSurface(
dstSurface,
@@ -151,14 +149,6 @@ private:
backgroundRect.left, backgroundRect.top,
Common::Rect(cachedSurface.w, cachedSurface.h));
}
-
- void alignRect(const Graphics::Surface &srcSurface, Common::Rect &rect) const override {
- // align on 16px
- rect.left &= 0xfff0;
- rect.right = (rect.right + 15) & 0xfff0;
- if (rect.right > srcSurface.w)
- rect.right = srcSurface.w;
- }
};
#endif
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index e013bcbbaec..043035a7e85 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -24,10 +24,9 @@
#include <mint/cookie.h>
#include <mint/falcon.h>
#include <mint/osbind.h>
+#include <mint/sysvars.h>
-#include "backends/graphics/atari/atari-graphics-asm.h"
#include "backends/graphics/atari/atari-graphics-superblitter.h"
-#include "backends/graphics/atari/videl-resolutions.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymap.h"
@@ -35,54 +34,171 @@
#include "common/str.h"
#include "common/textconsole.h" // for warning() & error()
#include "common/translation.h"
+#include "engines/engine.h"
#include "graphics/blit.h"
#include "gui/ThemeEngine.h"
+#define SCREEN_ACTIVE
+
bool g_unalignedPitch = false;
-#define SCREEN_ACTIVE
+// this is how screenptr should have been handled in TOS...
+#undef screenptr
+static volatile uintptr screenptr;
+static void VblHandler() {
+ if (screenptr) {
+#ifdef SCREEN_ACTIVE
+ if (hasSuperVidel()) {
+ // SuperVidel's XBIOS seems to switch to Super mode with BS8C...
+ VsetScreen(SCR_NOCHANGE, screenptr, SCR_NOCHANGE, SCR_NOCHANGE);
+ } else {
+ union { byte c[4]; uintptr p; } sptr;
+ sptr.p = screenptr;
+
+ *((volatile byte *)0xFFFF8201) = sptr.c[1];
+ *((volatile byte *)0xFFFF8203) = sptr.c[2];
+ *((volatile byte *)0xFFFF820D) = sptr.c[3];
+ }
+#endif
+ screenptr = 0;
+ }
+}
+
+static uint32 InstallVblHandler() {
+ uint32 installed = 0;
+ *vblsem = 0; // lock vbl
+
+ for (int i = 0; i < *nvbls; ++i) {
+ if (!(*_vblqueue)[i]) {
+ (*_vblqueue)[i] = VblHandler;
+ installed = 1;
+ break;
+ }
+ }
+
+ *vblsem = 1; // unlock vbl
+ return installed;
+}
+
+static uint32 UninstallVblHandler() {
+ uint32 uninstalled = 0;
+ *vblsem = 0; // lock vbl
+
+ for (int i = 0; i < *nvbls; ++i) {
+ if ((*_vblqueue)[i] == VblHandler) {
+ (*_vblqueue)[i] = NULL;
+ uninstalled = 1;
+ break;
+ }
+ }
+
+ *vblsem = 1; // unlock vbl
+ return uninstalled;
+}
+
+static int s_oldRez = -1;
+static int s_oldMode = -1;
+static void *s_oldPhysbase = nullptr;
+
+void AtariGraphicsShutdown() {
+ Supexec(UninstallVblHandler);
+
+ if (s_oldRez != -1) {
+ Setscreen(SCR_NOCHANGE, s_oldPhysbase, s_oldRez);
+ } else if (s_oldMode != -1) {
+ // prevent setting video base address just on the VDB line
+ Vsync();
+ VsetMode(s_oldMode);
+ VsetScreen(SCR_NOCHANGE, s_oldPhysbase, SCR_NOCHANGE, SCR_NOCHANGE);
+ }
+}
AtariGraphicsManager::AtariGraphicsManager() {
- _vgaMonitor = VgetMonitor() == MON_VGA;
+ debug("AtariGraphicsManager()");
+
+ enum {
+ VDO_NO_ATARI_HW = 0xffff,
+ VDO_ST = 0,
+ VDO_STE,
+ VDO_TT,
+ VDO_FALCON,
+ VDO_MILAN
+ };
+
+ long vdo = VDO_NO_ATARI_HW<<16;
+ Getcookie(C__VDO, &vdo);
+ vdo >>= 16;
+
+ _tt = (vdo == VDO_TT);
+
+ if (!_tt)
+ _vgaMonitor = VgetMonitor() == MON_VGA;
// make the standard GUI renderer default (!DISABLE_FANCY_THEMES implies anti-aliased rendering in ThemeEngine.cpp)
// (and without DISABLE_FANCY_THEMES we can't use 640x480 themes)
const char *standardThemeEngineName = GUI::ThemeEngine::findModeConfigName(GUI::ThemeEngine::kGfxStandard);
- ConfMan.registerDefault("gui_renderer", standardThemeEngineName);
if (!ConfMan.hasKey("gui_renderer"))
ConfMan.set("gui_renderer", standardThemeEngineName);
// make the built-in theme default to avoid long loading times
- ConfMan.registerDefault("gui_theme", "builtin");
if (!ConfMan.hasKey("gui_theme"))
ConfMan.set("gui_theme", "builtin");
+#ifndef DISABLE_FANCY_THEMES
// make "themes" the default theme path
ConfMan.registerDefault("themepath", "themes");
if (!ConfMan.hasKey("themepath"))
ConfMan.set("themepath", "themes");
+#endif
ConfMan.flushToDisk();
- // Generate RGB332 palette for the overlay
- for (uint i = 0; i < 256; i++) {
- _overlayPalette[i*3 + 0] = ((i >> 5) & 7) << 5;
- _overlayPalette[i*3 + 1] = ((i >> 2) & 7) << 5;
- _overlayPalette[i*3 + 2] = (i & 3) << 6;
+ // Generate RGB332/RGB121 palette for the overlay
+ const Graphics::PixelFormat &format = getOverlayFormat();
+ const int paletteSize = getOverlayPaletteSize();
+ for (int i = 0; i < paletteSize; i++) {
+ if (_tt) {
+ // Bits 15-12 Bits 11-8 Bits 7-4 Bits 3-0
+ // Reserved Red Green Blue
+ _overlayPalette.tt[i] = ((i >> format.rShift) & format.rMax()) << (8 + (format.rLoss - 4));
+ _overlayPalette.tt[i] |= ((i >> format.gShift) & format.gMax()) << (4 + (format.gLoss - 4));
+ _overlayPalette.tt[i] |= ((i >> format.bShift) & format.bMax()) << (0 + (format.bLoss - 4));
+ } else {
+ _overlayPalette.falcon[i].red = ((i >> format.rShift) & format.rMax()) << format.rLoss;
+ _overlayPalette.falcon[i].green |= ((i >> format.gShift) & format.gMax()) << format.gLoss;
+ _overlayPalette.falcon[i].blue |= ((i >> format.bShift) & format.bMax()) << format.bLoss;
+ }
+ }
+
+ // although we store/restore video hardware in OSystem_Atari,
+ // make sure that internal OS structures are updated correctly, too
+ if (_tt) {
+ s_oldRez = Getrez();
+ } else {
+ s_oldMode = VsetMode(VM_INQUIRE);
+ }
+ s_oldPhysbase = Physbase();
+
+ if (!Supexec(InstallVblHandler)) {
+ error("VBL handler was not installed");
}
g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
}
AtariGraphicsManager::~AtariGraphicsManager() {
+ debug("~AtariGraphicsManager()");
+
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+
+ AtariGraphicsShutdown();
}
bool AtariGraphicsManager::hasFeature(OSystem::Feature f) const {
switch (f) {
case OSystem::Feature::kFeatureAspectRatioCorrection:
//debug("hasFeature(kFeatureAspectRatioCorrection): %d", !_vgaMonitor);
- return !_vgaMonitor;
+ return !_tt && !_vgaMonitor;
case OSystem::Feature::kFeatureCursorPalette:
// FIXME: pretend to have cursor palette at all times, this function
// can get (and it is) called any time, before and after showOverlay()
@@ -152,20 +268,14 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
int error = OSystem::TransactionError::kTransactionSuccess;
- // always initialize (clear screen, mouse init, ...)
- //if (_pendingState == _currentState)
- // return static_cast<OSystem::TransactionError>(error);
-
if (_pendingState.format != PIXELFORMAT_CLUT8)
error |= OSystem::TransactionError::kTransactionFormatNotSupported;
- // TODO: Several engines support unusual resolutions like 256x240 (NES Maniac Mansion),
- // 512x342 (MacVenture, WAGE) or 544x332 (Myst)
- if ((_pendingState.width != 320 || (_pendingState.height != 200 && _pendingState.height != 240))
- && (_pendingState.width != 640 || (_pendingState.height != 400 && _pendingState.height != 480)))
+ if (_pendingState.width > getMaximumScreenWidth() || _pendingState.height > getMaximumScreenHeight())
error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
if (error != OSystem::TransactionError::kTransactionSuccess) {
+ warning("endGFXTransaction failed: %02x", (int)error);
// all our errors are fatal but engine.cpp takes only this one seriously
error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
return static_cast<OSystem::TransactionError>(error);
@@ -174,9 +284,10 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
_chunkySurface.init(_pendingState.width, _pendingState.height, _pendingState.width,
_chunkySurface.getPixels(), _pendingState.format);
- _screen[FRONT_BUFFER]->reset(_pendingState.width, _pendingState.height);
- _screen[BACK_BUFFER1]->reset(_pendingState.width, _pendingState.height);
- _screen[BACK_BUFFER2]->reset(_pendingState.width, _pendingState.height);
+ _screen[FRONT_BUFFER]->reset(_pendingState.width, _pendingState.height, 8);
+ _screen[BACK_BUFFER1]->reset(_pendingState.width, _pendingState.height, 8);
+ _screen[BACK_BUFFER2]->reset(_pendingState.width, _pendingState.height, 8);
+ screenptr = 0;
_workScreen = _screen[_pendingState.mode <= GraphicsMode::SingleBuffering ? FRONT_BUFFER : BACK_BUFFER1];
@@ -184,8 +295,8 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
if (_oldWorkScreen)
_oldWorkScreen = _workScreen;
- memset(_palette, 0, sizeof(_palette));
- _pendingScreenChange = kPendingScreenChangeScreen | kPendingScreenChangePalette;
+ _palette.clear();
+ _pendingScreenChange = kPendingScreenChangeMode | kPendingScreenChangeScreen | kPendingScreenChangePalette;
static bool firstRun = true;
if (firstRun) {
@@ -204,44 +315,94 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
void AtariGraphicsManager::setPalette(const byte *colors, uint start, uint num) {
//debug("setPalette: %d, %d", start, num);
- memcpy(&_palette[start * 3], colors, num * 3);
+ if (_tt) {
+ uint16 *pal = &_palette.tt[start];
+ for (uint i = 0; i < num; ++i) {
+ // Bits 15-12 Bits 11-8 Bits 7-4 Bits 3-0
+ // Reserved Red Green Blue
+ pal[i] = ((colors[i * 3 + 0] >> 4) & 0x0f) << 8;
+ pal[i] |= ((colors[i * 3 + 1] >> 4) & 0x0f) << 4;
+ pal[i] |= ((colors[i * 3 + 2] >> 4) & 0x0f);
+ }
+ } else {
+ _RGB *pal = &_palette.falcon[start];
+ for (uint i = 0; i < num; ++i) {
+ pal[i].red = colors[i * 3 + 0];
+ pal[i].green = colors[i * 3 + 1];
+ pal[i].blue = colors[i * 3 + 2];
+ }
+ }
+
_pendingScreenChange |= kPendingScreenChangePalette;
}
void AtariGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
//debug("grabPalette: %d, %d", start, num);
- memcpy(colors, &_palette[start * 3], num * 3);
+ if (_tt) {
+ const uint16 *pal = &_palette.tt[start];
+ for (uint i = 0; i < num; ++i) {
+ // Bits 15-12 Bits 11-8 Bits 7-4 Bits 3-0
+ // Reserved Red Green Blue
+ *colors++ = ((pal[i] >> 8) & 0x0f) << 4;
+ *colors++ = ((pal[i] >> 4) & 0x0f) << 4;
+ *colors++ = ((pal[i] ) & 0x0f) << 4;
+ }
+ } else {
+ const _RGB *pal = &_palette.falcon[start];
+ for (uint i = 0; i < num; ++i) {
+ *colors++ = pal[i].red;
+ *colors++ = pal[i].green;
+ *colors++ = pal[i].blue;
+ }
+ }
}
void AtariGraphicsManager::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) {
//debug("copyRectToScreen: %d, %d, %d(%d), %d", x, y, w, pitch, h);
- if (_currentState.mode != GraphicsMode::DirectRendering) {
- _chunkySurface.copyRectToSurface(buf, pitch, x, y, w, h);
- _workScreen->addDirtyRect(Common::Rect(x, y, x + w, y + h));
- } else {
- // TODO: c2p with 16pix align
- _workScreen->surf.copyRectToSurface(buf, pitch, x, y, w, h);
- _workScreen->addDirtyRect(Common::Rect(x, y, x + w, y + h));
+ Graphics::Surface &dstSurface = *lockScreen();
+ const Common::Rect rect = Common::Rect(x, y, x + w, y + h);
+ dstSurface.copyRectToSurface(buf, pitch, x, y, w, h);
+ _workScreen->addDirtyRect(dstSurface, rect);
+
+ if (_currentState.mode == GraphicsMode::DirectRendering) {
+ // TODO: c2p with 16pix align
updateScreen();
+ } else if (_currentState.mode == GraphicsMode::TripleBuffering) {
+ _screen[BACK_BUFFER2]->addDirtyRect(dstSurface, rect);
+ _screen[FRONT_BUFFER]->addDirtyRect(dstSurface, rect);
}
}
+// this is not really locking anything but it's an useful function
+// to return current rendering surface :)
Graphics::Surface *AtariGraphicsManager::lockScreen() {
//debug("lockScreen");
- return _currentState.mode != GraphicsMode::DirectRendering ? &_chunkySurface : &_workScreen->surf;
+ if (isOverlayVisible())
+ return &_overlaySurface; // used also for cursor clipping
+ else if (_currentState.mode != GraphicsMode::DirectRendering)
+ return &_chunkySurface;
+ else
+ return _workScreen->offsettedSurf;
}
void AtariGraphicsManager::unlockScreen() {
//debug("unlockScreen: %d x %d", _workScreen->surf.w, _workScreen->surf.h);
- _workScreen->addDirtyRect(Common::Rect(_workScreen->surf.w, _workScreen->surf.h));
+ const Graphics::Surface &dstSurface = *lockScreen();
+ const Common::Rect rect = Common::Rect(dstSurface.w, dstSurface.h);
+
+ _workScreen->addDirtyRect(dstSurface, rect);
if (_currentState.mode == GraphicsMode::DirectRendering)
updateScreen();
+ else if (_currentState.mode == GraphicsMode::TripleBuffering) {
+ _screen[BACK_BUFFER2]->addDirtyRect(dstSurface, rect);
+ _screen[FRONT_BUFFER]->addDirtyRect(dstSurface, rect);
+ }
}
void AtariGraphicsManager::fillScreen(uint32 col) {
@@ -255,6 +416,9 @@ void AtariGraphicsManager::fillScreen(uint32 col) {
void AtariGraphicsManager::updateScreen() {
//debug("updateScreen");
+ // avoid falling into the debugger (screen may not not initialized yet)
+ Common::setErrorHandler(nullptr);
+
if (_checkUnalignedPitch) {
const Common::ConfigManager::Domain *activeDomain = ConfMan.getActiveDomain();
if (activeDomain) {
@@ -274,100 +438,122 @@ void AtariGraphicsManager::updateScreen() {
}
// updates outOfScreen OR srcRect/dstRect (only if visible/needed)
- _cursor.update(_workScreen->surf, _workScreen->cursorPositionChanged || _workScreen->cursorSurfaceChanged);
+ _cursor.update(*lockScreen(), _workScreen->cursorPositionChanged || _workScreen->cursorSurfaceChanged);
- bool screenUpdated;
-
- lockSuperBlitter();
-
- assert(_currentState.mode >= GraphicsMode::DirectRendering && _currentState.mode <= GraphicsMode::TripleBuffering);
+ bool screenUpdated = false;
if (isOverlayVisible()) {
- screenUpdated = updateBuffered(_overlaySurface, _workScreen->dirtyRects);
assert(_workScreen == _screen[OVERLAY_BUFFER]);
-
- _workScreen->clearDirtyRects();
- unlockSuperBlitter();
- } else if (_currentState.mode == GraphicsMode::DirectRendering) {
- screenUpdated = updateDirect();
- assert(_workScreen == _screen[FRONT_BUFFER]);
-
- _workScreen->clearDirtyRects();
- unlockSuperBlitter();
- } else if (_currentState.mode == GraphicsMode::SingleBuffering) {
- screenUpdated = updateBuffered(_chunkySurface, _workScreen->dirtyRects);
- assert(_workScreen == _screen[FRONT_BUFFER]);
-
- _workScreen->clearDirtyRects();
- unlockSuperBlitter();
+ screenUpdated = updateScreenInternal(_overlaySurface, _workScreen->dirtyRects);
} else {
- assert(_workScreen == _screen[BACK_BUFFER1]);
-
- if (_workScreen->fullRedrawPending) {
- // scheduled fullscreen redraw in this frame...
- screenUpdated = updateBuffered(_chunkySurface, _workScreen->dirtyRects);
- } else if (_screen[BACK_BUFFER2]->fullRedrawPending) {
- // scheduled fullscreen redraw in previous frame...
- screenUpdated = updateBuffered(_chunkySurface, _screen[BACK_BUFFER2]->dirtyRects);
- } else {
- screenUpdated = updateBuffered(_chunkySurface, _workScreen->dirtyRects);
- // apply dirty rects from previous frame
- if (!_screen[BACK_BUFFER2]->dirtyRects.empty())
- screenUpdated |= updateBuffered(_chunkySurface, _screen[BACK_BUFFER2]->dirtyRects);
+ switch (_currentState.mode) {
+ case GraphicsMode::DirectRendering:
+ assert(_workScreen == _screen[FRONT_BUFFER]);
+ screenUpdated = updateScreenInternal(Graphics::Surface(), _workScreen->dirtyRects);
+ break;
+ case GraphicsMode::SingleBuffering:
+ assert(_workScreen == _screen[FRONT_BUFFER]);
+ screenUpdated = updateScreenInternal(_chunkySurface, _workScreen->dirtyRects);
+ break;
+ case GraphicsMode::TripleBuffering:
+ assert(_workScreen == _screen[BACK_BUFFER1]);
+ screenUpdated = updateScreenInternal(_chunkySurface, _workScreen->dirtyRects);
+ break;
}
+ }
- // clear the least recent dirty rects
- _screen[BACK_BUFFER2]->clearDirtyRects();
-
- // render into BACK_BUFFER1 and/or BACK_BUFFER2 and set the most recent one
- if (screenUpdated) {
- _screen[FRONT_BUFFER] = _screen[BACK_BUFFER1];
+ _workScreen->clearDirtyRects();
- Screen *tmp = _screen[BACK_BUFFER1];
- _screen[BACK_BUFFER1] = _screen[BACK_BUFFER2];
- _screen[BACK_BUFFER2] = tmp;
+ if (_pendingScreenChange & kPendingScreenChangeScreen) {
+ // can't call (V)SetScreen without Vsync()
+ screenptr = (uintptr)(isOverlayVisible() ? _workScreen->surf.getPixels() : _screen[FRONT_BUFFER]->surf.getPixels());
+ } else if (screenUpdated && !isOverlayVisible() && _currentState.mode == GraphicsMode::TripleBuffering) {
+ // Triple buffer:
+ // - alternate BACK_BUFFER1 and BACK_BUFFER2
+ // - check if FRONT_BUFFER has been displayed for at least one frame
+ // - display the most recent buffer (BACK_BUFFER2 in our case)
+ // - alternate BACK_BUFFER2 and FRONT_BUFFER (only if BACK_BUFFER2
+ // has been updated)
+
+ set_sysvar_to_short(vblsem, 0); // lock vbl
+
+ static long old_vbclock = get_sysvar(_vbclock);
+ long curr_vbclock = get_sysvar(_vbclock);
+
+ if (old_vbclock != curr_vbclock) {
+ // at least one vbl has passed since setting new video base
+ // guard BACK_BUFFER2 from overwriting while presented
+ Screen *tmp = _screen[BACK_BUFFER2];
+ _screen[BACK_BUFFER2] = _screen[FRONT_BUFFER];
+ _screen[FRONT_BUFFER] = tmp;
+
+ old_vbclock = curr_vbclock;
}
- // finish blitting before setting new screen address
- unlockSuperBlitter();
-
-#ifdef SCREEN_ACTIVE
- asm_screen_set_vram(_screen[FRONT_BUFFER]->surf.getPixels());
-#endif
- _workScreen = _screen[BACK_BUFFER1];
- }
+ // swap back buffers
+ Screen *tmp = _screen[BACK_BUFFER1];
+ _screen[BACK_BUFFER1] = _screen[BACK_BUFFER2];
+ _screen[BACK_BUFFER2] = tmp;
-#ifdef SCREEN_ACTIVE
- bool resolutionChanged = false;
+ // queue BACK_BUFFER2 with the most recent frame content
+ screenptr = (uintptr)_screen[BACK_BUFFER2]->surf.getPixels();
- if (_pendingScreenChange & kPendingScreenChangeOverlay) {
- if (_vgaMonitor)
- asm_screen_set_scp_res(scp_640x480x8_vga);
- else
- asm_screen_set_scp_res(scp_640x480x8_rgb);
+ set_sysvar_to_short(vblsem, 1); // unlock vbl
- asm_screen_set_vram(_screen[OVERLAY_BUFFER]->surf.getPixels());
- asm_screen_set_falcon_palette(_overlayPalette);
- resolutionChanged = true;
+ _workScreen = _screen[BACK_BUFFER1];
+ // BACK_BUFFER2: now contains finished frame
+ // FRONT_BUFFER is displayed and still contains previously finished frame
}
- if (_pendingScreenChange & kPendingScreenChangeScreen) {
- setVidelResolution();
- asm_screen_set_vram(_screen[FRONT_BUFFER]->surf.getPixels());
- resolutionChanged = true;
+#ifdef SCREEN_ACTIVE
+ if (_pendingScreenChange & kPendingScreenChangeMode) {
+ // Avoid changing video registers in the middle of rendering...
+ Vsync();
+
+ if (_workScreen->rez != -1) {
+ // unfortunately this reinitializes VDI, too
+ Setscreen(SCR_NOCHANGE, SCR_NOCHANGE, _workScreen->rez);
+ } else if (_workScreen->mode != -1) {
+ VsetMode(_workScreen->mode);
+ }
}
if (_pendingScreenChange & kPendingScreenChangePalette) {
- asm_screen_set_falcon_palette(_palette);
+ if (_tt)
+ EsetPalette(0, isOverlayVisible() ? getOverlayPaletteSize() : 256, _workScreen->palette->tt);
+ else
+ VsetRGB(0, isOverlayVisible() ? getOverlayPaletteSize() : 256, _workScreen->palette->falcon);
}
_pendingScreenChange = kPendingScreenChangeNone;
if (_oldAspectRatioCorrection != _aspectRatioCorrection) {
- if (!isOverlayVisible() && !resolutionChanged) {
- setVidelResolution();
+ if (!isOverlayVisible()) {
+ if (!_vgaMonitor) {
+ short mode = VsetMode(VM_INQUIRE);
+ if (_aspectRatioCorrection) {
+ // 60 Hz
+ mode &= ~PAL;
+ mode |= NTSC;
+ } else {
+ // 50 Hz
+ mode &= ~NTSC;
+ mode |= PAL;
+ }
+ VsetMode(mode);
+ } else if (hasSuperVidel()) {
+ // TODO: reduce to 200 scan lines?
+ } else if (!_tt) {
+ // TODO: increase vertical frequency?
+ } else {
+ // TODO: some tricks with TT's 480 lines?
+ }
+
+ _oldAspectRatioCorrection = _aspectRatioCorrection;
+ } else {
+ // ignore new value in overlay
+ _aspectRatioCorrection = _oldAspectRatioCorrection;
}
- _oldAspectRatioCorrection = _aspectRatioCorrection;
}
#endif
//debug("end of updateScreen");
@@ -383,22 +569,28 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
if (_overlayVisible)
return;
- _pendingScreenChange &= ~(kPendingScreenChangeScreen | kPendingScreenChangePalette);
- _pendingScreenChange |= kPendingScreenChangeOverlay;
-
if (_currentState.mode == GraphicsMode::DirectRendering) {
// make sure that _oldCursorRect is used to restore the original game graphics
// (but only if resolution hasn't changed, see endGFXTransaction())
bool wasVisible = showMouse(false);
- updateDirect();
- showMouse(wasVisible);
+
+ // revert back but don't update screen
+ _cursor.visible = wasVisible;
}
_cursor.swap();
_oldWorkScreen = _workScreen;
_workScreen = _screen[OVERLAY_BUFFER];
+ // do not cache dirtyRects and oldCursorRect
+ int bitsPerPixel = getOverlayFormat().isCLUT8() || getOverlayFormat() == PIXELFORMAT_RGB332 ? 8 : 4;
+ _workScreen->reset(getOverlayWidth(), getOverlayHeight(), bitsPerPixel);
+
+ _pendingScreenChange = kPendingScreenChangeMode | kPendingScreenChangeScreen | kPendingScreenChangePalette;
+
_overlayVisible = true;
+
+ updateScreen();
}
void AtariGraphicsManager::hideOverlay() {
@@ -407,12 +599,6 @@ void AtariGraphicsManager::hideOverlay() {
if (!_overlayVisible)
return;
- _pendingScreenChange &= ~kPendingScreenChangeOverlay;
- _pendingScreenChange |= (kPendingScreenChangeScreen | kPendingScreenChangePalette);
-
- // do not cache dirtyRects and oldCursorRect
- _workScreen->reset(getOverlayWidth(), getOverlayHeight());
-
_workScreen = _oldWorkScreen;
_oldWorkScreen = nullptr;
_cursor.swap();
@@ -420,7 +606,11 @@ void AtariGraphicsManager::hideOverlay() {
// FIXME: perhaps there's a better way but this will do for now
_checkUnalignedPitch = true;
+ _pendingScreenChange = kPendingScreenChangeMode | kPendingScreenChangeScreen | kPendingScreenChangePalette;
+
_overlayVisible = false;
+
+ updateScreen();
}
void AtariGraphicsManager::clearOverlay() {
@@ -429,62 +619,79 @@ void AtariGraphicsManager::clearOverlay() {
if (!_overlayVisible)
return;
+#ifndef DISABLE_FANCY_THEMES
const Graphics::Surface &sourceSurface =
- _currentState.mode == GraphicsMode::DirectRendering ? _screen[FRONT_BUFFER]->surf : _chunkySurface;
-
- int w = sourceSurface.w;
- int h = sourceSurface.h;
- int vOffset = 0;
+ _currentState.mode == GraphicsMode::DirectRendering ? *_screen[FRONT_BUFFER]->offsettedSurf : _chunkySurface;
- if (h == 200) {
- h = 240;
- vOffset = (240 - 200) / 2;
- } else if (h == 400) {
- h = 480;
- vOffset = (480 - 400) / 2;
- }
+ bool upscale = _overlaySurface.w / sourceSurface.w >= 2 && _overlaySurface.h / sourceSurface.h >= 2;
- bool upscale = false;
+ int w = upscale ? sourceSurface.w * 2 : sourceSurface.w;
+ int h = upscale ? sourceSurface.h * 2 : sourceSurface.h;
- if (_overlaySurface.w / w == 2 && _overlaySurface.h / h == 2) {
- upscale = true;
- vOffset *= 2;
- } else if (_overlaySurface.w / w != 1 && _overlaySurface.h / h != 1) {
- warning("Unknown overlay (%d, %d) / screen (%d, %d) ratio",
- _overlaySurface.w, _overlaySurface.h, w, h);
- return;
- }
+ int hzOffset = (_overlaySurface.w - w) / 2;
+ int vOffset = (_overlaySurface.h - h) / 2;
- memset(_overlaySurface.getBasePtr(0, 0), 0, _overlaySurface.pitch * vOffset);
+ int pitch = hzOffset * 2 + (upscale ? _overlaySurface.pitch : 0);
- // Transpose from game palette to RGB332 (overlay palette)
+ // Transpose from game palette to RGB332/RGB121 (overlay palette)
const byte *src = (const byte*)sourceSurface.getPixels();
- byte *dst = (byte*)_overlaySurface.getBasePtr(0, vOffset);
+ byte *dst = (byte *)_overlaySurface.getBasePtr(hzOffset, vOffset);
+
+ // for TT: 8/4/0 + (xLoss - 4) + xShift
+ static const int rShift = (_tt ? (8 - 4) : 0)
+ + _overlaySurface.format.rLoss - _overlaySurface.format.rShift;
+ static const int gShift = (_tt ? (4 - 4) : 0)
+ + _overlaySurface.format.gLoss - _overlaySurface.format.gShift;
+ static const int bShift = (_tt ? (0 - 4) : 0)
+ + _overlaySurface.format.bLoss - _overlaySurface.format.bShift;
+
+ static const int rMask = _overlaySurface.format.rMax() << _overlaySurface.format.rShift;
+ static const int gMask = _overlaySurface.format.gMax() << _overlaySurface.format.gShift;
+ static const int bMask = _overlaySurface.format.bMax() << _overlaySurface.format.bShift;
for (int y = 0; y < sourceSurface.h; y++) {
for (int x = 0; x < sourceSurface.w; x++) {
- const byte col = *src++;
- const byte pixel = (_palette[3*col + 0] & 0xe0)
- | ((_palette[3*col + 1] >> 3) & 0x1c)
- | ((_palette[3*col + 2] >> 6) & 0x03);
+ byte pixel;
+
+ if (_tt) {
+ // Bits 15-12 Bits 11-8 Bits 7-4 Bits 3-0
+ // Reserved Red Green Blue
+ const uint16 &col = _palette.tt[*src++];
+ pixel = ((col >> rShift) & rMask)
+ | ((col >> gShift) & gMask)
+ | ((col >> bShift) & bMask);
+ } else {
+ const _RGB &col = _palette.falcon[*src++];
+ pixel = ((col.red >> rShift) & rMask)
+ | ((col.green >> gShift) & gMask)
+ | ((col.blue >> bShift) & bMask);
+ }
if (upscale) {
*(dst + _overlaySurface.pitch) = pixel;
*dst++ = pixel;
*(dst + _overlaySurface.pitch) = pixel;
- *dst++ = pixel;
- } else {
- *dst++ = pixel;
}
+ *dst++ = pixel;
}
- if (upscale)
- dst += _overlaySurface.pitch;
+ dst += pitch;
}
- memset(_overlaySurface.getBasePtr(0, _overlaySurface.h - vOffset), 0, _overlaySurface.pitch * vOffset);
-
- _screen[OVERLAY_BUFFER]->addDirtyRect(Common::Rect(_screen[OVERLAY_BUFFER]->surf.w, _screen[OVERLAY_BUFFER]->surf.h));
+ // top rect
+ memset(_overlaySurface.getBasePtr(0, 0), 0, vOffset * _overlaySurface.pitch);
+ // bottom rect
+ memset(_overlaySurface.getBasePtr(0, _overlaySurface.h - vOffset), 0, vOffset * _overlaySurface.pitch);
+ // left rect
+ _overlaySurface.fillRect(Common::Rect(0, vOffset, hzOffset, _overlaySurface.h - vOffset), 0);
+ // right rect
+ _overlaySurface.fillRect(Common::Rect(_overlaySurface.w - hzOffset, vOffset, _overlaySurface.w, _overlaySurface.h - vOffset), 0);
+
+ _screen[OVERLAY_BUFFER]->addDirtyRect(_overlaySurface, Common::Rect(_overlaySurface.w, _overlaySurface.h));
+#else
+ // for cursor background and non-aligned rects
+ memset(_overlaySurface.getPixels(), 0, _overlaySurface.h * _overlaySurface.pitch);
+#endif
}
void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
@@ -494,17 +701,22 @@ void AtariGraphicsManager::grabOverlay(Graphics::Surface &surface) const {
assert(surface.h >= _overlaySurface.h);
assert(surface.format.bytesPerPixel == _overlaySurface.format.bytesPerPixel);
+#ifndef DISABLE_FANCY_THEMES
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);
+#else
+ // assumes that the first dirty rect in copyRectToOverlay is always fullscreen
+ memset(surface.getPixels(), 0, surface.h * surface.pitch);
+#endif
}
void AtariGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) {
//debug("copyRectToOverlay: %d, %d, %d(%d), %d", x, y, w, pitch, h);
_overlaySurface.copyRectToSurface(buf, pitch, x, y, w, h);
- _screen[OVERLAY_BUFFER]->addDirtyRect(Common::Rect(x, y, x + w, y + h));
+ _screen[OVERLAY_BUFFER]->addDirtyRect(_overlaySurface, Common::Rect(x, y, x + w, y + h));
}
bool AtariGraphicsManager::showMouse(bool visible) {
@@ -516,6 +728,11 @@ bool AtariGraphicsManager::showMouse(bool visible) {
bool last = _cursor.visible;
_cursor.visible = visible;
+
+ cursorVisibilityChanged();
+ // don't rely on engines to call it (if they don't it confuses the cursor restore logic)
+ updateScreen();
+
return last;
}
@@ -546,7 +763,7 @@ void AtariGraphicsManager::setCursorPalette(const byte *colors, uint start, uint
}
void AtariGraphicsManager::updateMousePosition(int deltaX, int deltaY) {
- _cursor.updatePosition(deltaX, deltaY, _workScreen->surf);
+ _cursor.updatePosition(deltaX, deltaY, *lockScreen());
cursorPositionChanged();
}
@@ -580,11 +797,12 @@ Common::Keymap *AtariGraphicsManager::getKeymap() const {
void AtariGraphicsManager::allocateSurfaces() {
for (int i : { FRONT_BUFFER, BACK_BUFFER1, BACK_BUFFER2 }) {
- _screen[i] = new Screen(this, SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT_CLUT8);
+ _screen[i] = new Screen(this, getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8, &_palette);
}
- _screen[OVERLAY_BUFFER] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat());
- _chunkySurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT_CLUT8);
+ _screen[OVERLAY_BUFFER] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
+
+ _chunkySurface.create(getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8);
_overlaySurface.create(getOverlayWidth(), getOverlayHeight(), getOverlayFormat());
}
@@ -599,150 +817,153 @@ void AtariGraphicsManager::freeSurfaces() {
_overlaySurface.free();
}
-void AtariGraphicsManager::setVidelResolution() const {
- if (_vgaMonitor) {
- // TODO: aspect ratio correction
- // TODO: supervidel 320x240...
- if (_workScreen->surf.w == 320) {
- if (_workScreen->surf.h == 200)
- asm_screen_set_scp_res(scp_320x200x8_vga);
- else
- asm_screen_set_scp_res(scp_320x240x8_vga);
- } else {
- if (_workScreen->surf.h == 400)
- asm_screen_set_scp_res(scp_640x400x8_vga);
- else
- asm_screen_set_scp_res(scp_640x480x8_vga);
- }
- } else {
- if (_workScreen->surf.w == 320) {
- if (_workScreen->surf.h == 240)
- asm_screen_set_scp_res(scp_320x240x8_rgb);
- else if (_workScreen->surf.h == 200 && _aspectRatioCorrection)
- asm_screen_set_scp_res(scp_320x200x8_rgb60);
- else
- asm_screen_set_scp_res(scp_320x200x8_rgb);
- } else {
- if (_workScreen->surf.h == 480)
- asm_screen_set_scp_res(scp_640x480x8_rgb);
- else if (_workScreen->surf.h == 400 && _aspectRatioCorrection)
- asm_screen_set_scp_res(scp_640x400x8_rgb60);
- else
- asm_screen_set_scp_res(scp_640x400x8_rgb);
- }
- }
-}
-
-bool AtariGraphicsManager::updateDirect() {
- const Common::Rect &dirtyScreenRect = _workScreen->dirtyRects.empty() ? Common::Rect() : _workScreen->dirtyRects.front();
- bool &cursorPositionChanged = _workScreen->cursorPositionChanged;
- bool &cursorSurfaceChanged = _workScreen->cursorSurfaceChanged;
- Common::Rect &oldCursorRect = _workScreen->oldCursorRect;
+void AtariGraphicsManager::convertRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
+ int destX, int destY, const Common::Rect &subRect, uint32 key,
+ const byte srcPalette[256*3]) const {
+ if (!dstSurface.format.isCLUT8()) {
+ assert(srcSurface.format == PIXELFORMAT_CLUT8);
- bool updated = false;
-
- if (_cursor.outOfScreen)
- return updated;
-
- bool drawCursor = cursorPositionChanged || cursorSurfaceChanged;
+ static int rShift, gShift, bShift;
+ static int rMask, gMask, bMask;
+ static Graphics::PixelFormat format;
- if (!drawCursor && _cursor.visible && !dirtyScreenRect.isEmpty())
- drawCursor = dirtyScreenRect.intersects(_cursor.dstRect);
+ if (dstSurface.format != format) {
+ format = dstSurface.format;
- static Graphics::Surface cachedCursorSurface;
+ rShift = format.rLoss - format.rShift;
+ gShift = format.gLoss - format.gShift;
+ bShift = format.bLoss - format.bShift;
- if (!oldCursorRect.isEmpty() && !dirtyScreenRect.isEmpty()) {
- const Common::Rect intersectingRect = dirtyScreenRect.findIntersectingRect(oldCursorRect);
- if (!intersectingRect.isEmpty()) {
- // update cached surface
- const Graphics::Surface intersectingScreenSurface = _workScreen->surf.getSubArea(intersectingRect);
- cachedCursorSurface.copyRectToSurface(
- intersectingScreenSurface,
- intersectingRect.left - oldCursorRect.left,
- intersectingRect.top - oldCursorRect.top,
- Common::Rect(intersectingScreenSurface.w, intersectingScreenSurface.h));
+ rMask = format.rMax() << format.rShift;
+ gMask = format.gMax() << format.gShift;
+ bMask = format.bMax() << format.bShift;
}
- }
-
- if ((cursorPositionChanged || !_cursor.visible) && !oldCursorRect.isEmpty()) {
- _workScreen->surf.copyRectToSurface(
- cachedCursorSurface,
- oldCursorRect.left, oldCursorRect.top,
- Common::Rect(oldCursorRect.width(), oldCursorRect.height()));
- oldCursorRect = Common::Rect();
-
- updated = true;
- }
-
- if (drawCursor && _cursor.visible) {
- //debug("Redraw cursor (direct): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+ // Convert CLUT8 to RGB332/RGB121 palette and do copyRectToSurfaceWithKey() at the same time
+ const byte *src = (const byte*)srcSurface.getBasePtr(subRect.left, subRect.top);
+ byte *dst = (byte*)dstSurface.getBasePtr(destX, destY);
+
+ const int16 w = subRect.width();
+ const int16 h = subRect.height();
+
+ for (int16 y = 0; y < h; ++y) {
+ for (int16 x = 0; x < w; ++x) {
+ const uint32 color = *src++;
+ if (color != key) {
+ *dst++ = ((srcPalette[color*3 + 0] >> rShift) & rMask)
+ | ((srcPalette[color*3 + 1] >> gShift) & gMask)
+ | ((srcPalette[color*3 + 2] >> bShift) & bMask);
+ } else {
+ dst++;
+ }
+ }
- if (cachedCursorSurface.w != _cursor.dstRect.width() || cachedCursorSurface.h != _cursor.dstRect.height()) {
- cachedCursorSurface.create(_cursor.dstRect.width(), _cursor.dstRect.height(), _cursor.surface.format);
+ src += (srcSurface.pitch - w);
+ dst += (dstSurface.pitch - w);
}
-
- // background has been restored, so it's safe to read _workScreen
- if (oldCursorRect.isEmpty())
- cachedCursorSurface.copyRectToSurface(_workScreen->surf, 0, 0, _cursor.dstRect);
-
- _workScreen->surf.copyRectToSurfaceWithKey(
- _cursor.surface,
- _cursor.dstRect.left, _cursor.dstRect.top,
- _cursor.srcRect,
- _cursor.keycolor);
-
- cursorPositionChanged = cursorSurfaceChanged = false;
- oldCursorRect = _cursor.dstRect;
-
- updated = true;
+ } else {
+ dstSurface.copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, key);
}
-
- return updated;
}
-bool AtariGraphicsManager::updateBuffered(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects) {
- //debug("updateBuffered: %d", dirtyRects.size());
+bool AtariGraphicsManager::updateScreenInternal(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects) {
+ //debug("updateScreenInternal: %d", (int)dirtyRects.size());
- // workscreen related setting; these are used even if called repeatedly for triple buffering
- Graphics::Surface &dstSurface = _workScreen->surf;
+ Graphics::Surface *dstSurface = _workScreen->offsettedSurf;
bool &cursorPositionChanged = _workScreen->cursorPositionChanged;
bool &cursorSurfaceChanged = _workScreen->cursorSurfaceChanged;
+ bool &cursorVisibilityChanged = _workScreen->cursorVisibilityChanged;
Common::Rect &oldCursorRect = _workScreen->oldCursorRect;
+ const bool &fullRedraw = _workScreen->fullRedraw;
+#ifndef DISABLE_FANCY_THEMES
+ const bool directRendering = !isOverlayVisible() && _currentState.mode == GraphicsMode::DirectRendering;
+#else
+ // hopefully compiler optimizes all the branching out
+ const bool directRendering = false;
+#endif
bool updated = false;
- bool drawCursor = cursorPositionChanged || cursorSurfaceChanged;;
+
+ const bool cursorDrawEnabled = !_cursor.outOfScreen && _cursor.visible;
+ bool drawCursor = cursorDrawEnabled
+ && (cursorPositionChanged || cursorSurfaceChanged || cursorVisibilityChanged || fullRedraw);
+
+ bool restoreCursor = !fullRedraw && !oldCursorRect.isEmpty()
+ && (cursorPositionChanged || cursorSurfaceChanged || (cursorVisibilityChanged && !_cursor.visible));
+
+ static Graphics::Surface cachedCursorSurface;
+
+ lockSuperBlitter();
for (auto it = dirtyRects.begin(); it != dirtyRects.end(); ++it) {
- if (!drawCursor && !_cursor.outOfScreen && _cursor.visible)
+ if (cursorDrawEnabled && !drawCursor)
drawCursor = it->intersects(_cursor.dstRect);
- copyRectToSurface(dstSurface, srcSurface, it->left, it->top, *it);
-
- updated = true;
+ if (restoreCursor)
+ restoreCursor = !it->contains(oldCursorRect);
+
+ if (!directRendering) {
+ copyRectToSurface(*dstSurface, srcSurface, it->left, it->top, *it);
+ updated = true;
+ } else if (!oldCursorRect.isEmpty()) {
+ const Common::Rect intersectingRect = it->findIntersectingRect(oldCursorRect);
+ if (!intersectingRect.isEmpty()) {
+ // new content has been drawn over stored surface => update
+ // TODO: if restoreCursor == true, update only the NON-intersecting part
+ const Graphics::Surface intersectingScreenSurface = dstSurface->getSubArea(intersectingRect);
+ cachedCursorSurface.copyRectToSurface(
+ intersectingScreenSurface,
+ intersectingRect.left - oldCursorRect.left,
+ intersectingRect.top - oldCursorRect.top,
+ Common::Rect(intersectingScreenSurface.w, intersectingScreenSurface.h));
+ }
+ }
}
- if (_cursor.outOfScreen)
- return updated;
+ if (restoreCursor) {
+ //debug("Restore cursor: %d %d %d %d", oldCursorRect.left, oldCursorRect.top, oldCursorRect.width(), oldCursorRect.height());
- if ((cursorPositionChanged || !_cursor.visible) && !oldCursorRect.isEmpty()) {
- alignRect(dstSurface, oldCursorRect);
- copyRectToSurface(
- dstSurface, srcSurface,
- oldCursorRect.left, oldCursorRect.top,
- oldCursorRect);
+ if (!directRendering) {
+ // align on 16px (i.e. 16 bytes -> optimize for C2P, MOVE16 or just 16-byte cache lines)
+ oldCursorRect.left &= 0xfff0;
+ oldCursorRect.right = (oldCursorRect.right + 15) & 0xfff0;
+
+ copyRectToSurface(
+ *dstSurface, srcSurface,
+ oldCursorRect.left, oldCursorRect.top,
+ oldCursorRect);
+ } else {
+ copyRectToSurface(
+ *dstSurface, cachedCursorSurface,
+ oldCursorRect.left, oldCursorRect.top,
+ Common::Rect(oldCursorRect.width(), oldCursorRect.height()));
+ }
oldCursorRect = Common::Rect();
updated = true;
}
- if (drawCursor && _cursor.visible) {
+ unlockSuperBlitter();
+
+ if (drawCursor) {
//debug("Redraw cursor: %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
+
+ if (directRendering) {
+ if (cachedCursorSurface.w != _cursor.dstRect.width() || cachedCursorSurface.h != _cursor.dstRect.height())
+ cachedCursorSurface.create(_cursor.dstRect.width(), _cursor.dstRect.height(), _cursor.surface.format);
+
+ // background has been restored, so it's safe to read from destination surface again
+ if (oldCursorRect.isEmpty())
+ cachedCursorSurface.copyRectToSurface(*dstSurface, 0, 0, _cursor.dstRect);
+ }
+
copyRectToSurfaceWithKey(
- dstSurface, srcSurface, _cursor.surface,
+ *dstSurface, _cursor.surface,
_cursor.dstRect.left, _cursor.dstRect.top,
- _cursor.srcRect, _cursor.keycolor, _cursor.palette);
+ _cursor.srcRect,
+ _cursor.keycolor,
+ srcSurface, _cursor.palette);
cursorPositionChanged = cursorSurfaceChanged = false;
oldCursorRect = _cursor.dstRect;
@@ -750,14 +971,18 @@ bool AtariGraphicsManager::updateBuffered(const Graphics::Surface &srcSurface, c
updated = true;
}
+ cursorVisibilityChanged = false;
+
return updated;
}
-AtariGraphicsManager::Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format)
+AtariGraphicsManager::Screen::Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette_)
: _manager(manager) {
const AtariMemAlloc &allocFunc = _manager->getStRamAllocFunc();
- surf.init(width, height, (width * format.bytesPerPixel + ALIGN - 1) & (-ALIGN), nullptr, format);
+ palette = palette_;
+
+ surf.init(width, height, width * format.bytesPerPixel, nullptr, format);
void *pixelsUnaligned = allocFunc(sizeof(uintptr) + (surf.h * surf.pitch) + ALIGN - 1);
if (!pixelsUnaligned) {
@@ -770,6 +995,8 @@ AtariGraphicsManager::Screen::Screen(AtariGraphicsManager *manager, int width, i
*((uintptr *)surf.getPixels() - 1) = (uintptr)pixelsUnaligned;
memset(surf.getPixels(), 0, surf.h * surf.pitch);
+
+ _offsettedSurf.init(surf.w, surf.h, surf.pitch, surf.getPixels(), surf.format);
}
AtariGraphicsManager::Screen::~Screen() {
@@ -778,21 +1005,89 @@ AtariGraphicsManager::Screen::~Screen() {
freeFunc((void *)*((uintptr *)surf.getPixels() - 1));
}
-void AtariGraphicsManager::Screen::addDirtyRect(Common::Rect rect) {
- if (_fullRedraw)
+void AtariGraphicsManager::Screen::reset(int width, int height, int bitsPerPixel) {
+ cursorPositionChanged = true;
+ cursorSurfaceChanged = false;
+ cursorVisibilityChanged = false;
+ clearDirtyRects();
+ oldCursorRect = Common::Rect();
+ rez = -1;
+ mode = -1;
+
+ // erase old screen
+ surf.fillRect(Common::Rect(surf.w, surf.h), 0);
+
+ if (_manager->_tt) {
+ if (width <= 320 && height <= 240) {
+ surf.w = 320;
+ surf.h = 240;
+ surf.pitch = 2*surf.w;
+ rez = kRezValueTTLow;
+ } else {
+ surf.w = 640;
+ surf.h = 480;
+ surf.pitch = surf.w;
+ rez = kRezValueTTMid;
+ }
+ } else {
+ mode = VsetMode(VM_INQUIRE) & PAL;
+
+ if (_manager->_vgaMonitor) {
+ mode |= VGA | (bitsPerPixel == 4 ? BPS4 : (hasSuperVidel() ? BPS8C : BPS8));
+
+ if (width <= 320 && height <= 240) {
+ surf.w = 320;
+ surf.h = 240;
+ mode |= VERTFLAG | COL40;
+ } else {
+ surf.w = 640;
+ surf.h = 480;
+ mode |= COL80;
+ }
+ } else {
+ mode |= TV | BPS8;
+
+ if (width <= 320 && height <= 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;
+ mode |= OVERSCAN | COL40;
+ } else if (width <= 640 && height <= 400) {
+ surf.w = 640;
+ surf.h = 400;
+ mode |= VERTFLAG | COL80;
+ } else {
+ surf.w = 640*1.2;
+ surf.h = 400*1.2;
+ mode |= VERTFLAG | OVERSCAN | COL80;
+ }
+ }
+
+ surf.pitch = surf.w;
+ }
+
+ _offsettedSurf.init(width, height, surf.pitch, surf.getBasePtr((surf.w - width) / 2, (surf.h - height) / 2), surf.format);
+}
+
+void AtariGraphicsManager::Screen::addDirtyRect(const Graphics::Surface &srcSurface, Common::Rect rect) {
+ if (fullRedraw)
return;
- _manager->alignRect(surf, rect);
+ // align on 16px (i.e. 16 bytes -> optimize for C2P, MOVE16 or just 16-byte cache lines)
+ rect.left &= 0xfff0;
+ rect.right = (rect.right + 15) & 0xfff0;
- // TODO: this assumes that screen resolution == chunky buffer resolution
- if ((rect.width() == surf.w && rect.height() == surf.h)
+ if ((rect.width() == srcSurface.w && rect.height() == srcSurface.h)
|| dirtyRects.size() == dirtyRects.capacity()) {
- //debug("addDirtyRect[%d]: purge %d x %d", (int)dirtyRects.size(), surf.w, surf.h);
+ //debug("addDirtyRect[%d]: purge %d x %d", (int)dirtyRects.size(), srcSurface.w, srcSurface.h);
dirtyRects.clear();
- dirtyRects.push_back(Common::Rect(surf.w, surf.h));
+ dirtyRects.push_back(Common::Rect(srcSurface.w, srcSurface.h));
- _fullRedraw = true;
+ fullRedraw = true;
return;
}
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 8b52f1bce22..49c991b63d4 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -25,6 +25,7 @@
#include "backends/graphics/graphics.h"
#include <mint/osbind.h>
+#include <mint/ostruct.h>
#include <vector>
#include "common/events.h"
@@ -67,12 +68,18 @@ public:
void showOverlay(bool inGUI) override;
void hideOverlay() override;
bool isOverlayVisible() const override { return _overlayVisible; }
- Graphics::PixelFormat getOverlayFormat() const override { return PIXELFORMAT_RGB332; }
+ Graphics::PixelFormat getOverlayFormat() const override {
+#ifndef DISABLE_FANCY_THEMES
+ return _tt ? PIXELFORMAT_RGB121 : PIXELFORMAT_RGB332;
+#else
+ return PIXELFORMAT_RGB121;
+#endif
+ }
void clearOverlay() override;
void grabOverlay(Graphics::Surface &surface) const override;
void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) override;
int16 getOverlayHeight() const override { return 480; }
- int16 getOverlayWidth() const override { return 640; }
+ int16 getOverlayWidth() const override { return _vgaMonitor ? 640 : 640*1.2; }
bool showMouse(bool visible) override;
void warpMouse(int x, int y) override;
@@ -89,12 +96,16 @@ public:
protected:
const Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::createFormatCLUT8();
const Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
+ const Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
typedef void* (*AtariMemAlloc)(size_t bytes);
typedef void (*AtariMemFree)(void *ptr);
void allocateSurfaces();
void freeSurfaces();
+ void convertRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
+ int destX, int destY, const Common::Rect &subRect, uint32 key,
+ const byte srcPalette[256*3]) const;
enum class GraphicsMode : int {
DirectRendering = 0,
@@ -117,19 +128,6 @@ protected:
GraphicsState _pendingState{ (GraphicsMode)getDefaultGraphicsMode() };
private:
- enum {
- // maximum screen dimensions
- SCREEN_WIDTH = 640,
- SCREEN_HEIGHT = 480
- };
-
- virtual AtariMemAlloc getStRamAllocFunc() const {
- return [](size_t bytes) { return (void*)Mxalloc(bytes, MX_STRAM); };
- }
- virtual AtariMemFree getStRamFreeFunc() const {
- return [](void *ptr) { Mfree(ptr); };
- }
-
// use std::vector as its clear() doesn't reset capacity
using DirtyRects = std::vector<Common::Rect>;
@@ -137,22 +135,37 @@ private:
kActionToggleAspectRatioCorrection = 100,
};
- void setVidelResolution() const;
+ enum SteTtRezValue {
+ kRezValueSTLow = 0, // 320x200 at 4bpp, ST palette
+ kRezValueSTMid = 1, // 640x200 at 2bpp, ST palette
+ kRezValueSTHigh = 2, // 640x400 at 1bpp, ST palette
+ kRezValueTTLow = 7, // 320x480 at 8bpp, TT palette
+ kRezValueTTMid = 4, // 640x480 at 4bpp, TT palette
+ kRezValueTTHigh = 6 // 1280x960 at 1bpp, TT palette
+ };
- bool updateDirect();
- bool updateBuffered(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects);
+ int16 getMaximumScreenHeight() const { return 480; }
+ int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 640 : 640*1.2); }
+
+ bool updateScreenInternal(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects);
+
+ 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 copyRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &bgSurface,
- const Graphics::Surface &srcSurface, int destX, int destY,
- const Common::Rect &subRect, uint32 key, const byte srcPalette[256*3]) const {
- dstSurface.copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, key);
+ virtual void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface, const Graphics::Surface &srcSurface,
+ int destX, int destY, const Common::Rect &subRect, uint32 key,
+ const Graphics::Surface &bgSurface, const byte srcPalette[256*3]) const {
+ convertRectToSurfaceWithKey(dstSurface, srcSurface, destX, destY, subRect, key, srcPalette);
}
- virtual void alignRect(const Graphics::Surface &srcSurface, Common::Rect &rect) const {}
void cursorPositionChanged() {
if (_overlayVisible) {
@@ -176,7 +189,27 @@ private:
}
}
+ void cursorVisibilityChanged() {
+ if (_overlayVisible) {
+ _screen[OVERLAY_BUFFER]->cursorVisibilityChanged = true;
+ } else {
+ _screen[FRONT_BUFFER]->cursorVisibilityChanged
+ = _screen[BACK_BUFFER1]->cursorVisibilityChanged
+ = _screen[BACK_BUFFER2]->cursorVisibilityChanged
+ = true;
+ }
+ }
+
+ int getOverlayPaletteSize() const {
+#ifndef DISABLE_FANCY_THEMES
+ return _tt ? 16 : 256;
+#else
+ return 16;
+#endif
+ }
+
bool _vgaMonitor = true;
+ bool _tt = false;
bool _aspectRatioCorrection = false;
bool _oldAspectRatioCorrection = false;
@@ -184,7 +217,7 @@ private:
enum PendingScreenChange {
kPendingScreenChangeNone = 0,
- kPendingScreenChangeOverlay = 1<<0,
+ kPendingScreenChangeMode = 1<<0,
kPendingScreenChangeScreen = 1<<1,
kPendingScreenChangePalette = 1<<2
};
@@ -198,44 +231,48 @@ private:
BUFFER_COUNT
};
+ class Palette {
+ public:
+ void clear() {
+ memset(data, 0, sizeof(data));
+ }
+
+ uint16 *const tt = reinterpret_cast<uint16*>(data);
+ _RGB *const falcon = reinterpret_cast<_RGB*>(data);
+
+ private:
+ byte data[256*4] = {};
+ };
+
struct Screen {
- Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format);
+ Screen(AtariGraphicsManager *manager, int width, int height, const Graphics::PixelFormat &format, const Palette *palette);
~Screen();
- void reset(int width, int height) {
- cursorPositionChanged = true;
- cursorSurfaceChanged = false;
- clearDirtyRects();
- oldCursorRect = Common::Rect();
-
- // erase old screen
- surf.fillRect(Common::Rect(surf.w, surf.h), 0);
- // set new dimensions
- surf.pitch = width;
- surf.w = width;
- surf.h = height;
- }
-
- void addDirtyRect(Common::Rect rect);
+ void reset(int width, int height, int bitsPerPixel);
+ void addDirtyRect(const Graphics::Surface &srcSurface, Common::Rect rect);
void clearDirtyRects() {
dirtyRects.clear();
- _fullRedraw = false;
+ fullRedraw = false;
}
- const bool &fullRedrawPending = _fullRedraw;
-
Graphics::Surface surf;
+ const Palette *palette;
bool cursorPositionChanged = true;
bool cursorSurfaceChanged = false;
+ bool cursorVisibilityChanged = false;
DirtyRects dirtyRects = DirtyRects(512); // reserve 512 rects
+ bool fullRedraw = false;
Common::Rect oldCursorRect;
+ int rez = -1;
+ int mode = -1;
+ Graphics::Surface *const offsettedSurf = &_offsettedSurf;
private:
static constexpr size_t ALIGN = 16; // 16 bytes
- bool _fullRedraw = false;
AtariGraphicsManager *_manager;
+ Graphics::Surface _offsettedSurf;
};
Screen *_screen[BUFFER_COUNT] = {};
Screen *_workScreen = nullptr;
@@ -294,8 +331,8 @@ private:
int hotspotY;
} _cursor;
- byte _palette[256*3] = {};
- byte _overlayPalette[256*3] = {};
+ Palette _palette;
+ Palette _overlayPalette;
};
#endif
diff --git a/backends/graphics/atari/atari_c2p-asm.S b/backends/graphics/atari/atari_c2p-asm.S
index 03b57afc380..32c4a0bf292 100644
--- a/backends/graphics/atari/atari_c2p-asm.S
+++ b/backends/graphics/atari/atari_c2p-asm.S
@@ -23,7 +23,10 @@
| See https://github.com/Kalmalyzer/kalms-c2p
.globl _asm_c2p1x1_8
+ .globl _asm_c2p1x1_8_tt
.globl _asm_c2p1x1_8_rect
+ .globl _asm_c2p1x1_4
+ .globl _asm_c2p1x1_4_rect
.text
@@ -225,6 +228,221 @@ c2p1x1_8_start:
rts
+| void asm_c2p1x1_8_tt(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen, uint32 screenPitch);
+_asm_c2p1x1_8_tt:
+ movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
+
+ 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 sp,old_sp
+
+ move.l d0,screen_pitch
+
+ lsr.l #1,d0
+ lea (a1,d0.l),a7 | a7: end of first dst line
+
+ move.l d0,screen_offset
+
+ move.l #0x0f0f0f0f,d4
+ move.l #0x00ff00ff,d5
+ move.l #0x55555555,d6
+
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ bra.s c2p1x1_8_tt_start
+
+c2p1x1_8_tt_pix16:
+ move.l (a0)+,d0
+ move.l (a0)+,d1
+ move.l (a0)+,d2
+ move.l (a0)+,d3
+
+ | a7a6a5a4a3a2a1a0 b7b6b5b4b3b2b1b0 c7c6c5c4c3c2c1c0 d7d6d5d4d3d2d1d0
+ | e7e6e5e4e3e2e1e0 f7f6f5f4f3f2f1f0 g7g6g5g4g3g2g1g0 h7h6h5h4h3h2h1h0
+ | i7i6i5i4i3i2i1i0 j7j6j5j4j3j2j1j0 k7k6k5k4k3k2k1k0 l7l6l5l4l3l2l1l0
+ | m7m6m5m4m3m2m1m0 n7n6n5n4n3n2n1n0 o7o6o5o4o3o2o1o0 p7p6p5p4p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #4,d7
+ move.l a3,(a1)+
+ eor.l d0,d7
+ and.l d4,d7
+ eor.l d7,d0
+ lsl.l #4,d7
+ eor.l d7,d1
+ move.l d3,d7
+ lsr.l #4,d7
+ eor.l d2,d7
+ and.l d4,d7
+ eor.l d7,d2
+ move.l a4,(a1)+
+ lsl.l #4,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 b7b6b5b4f7f6f5f4 c7c6c5c4g7g6g5g4 d7d6d5d4h7h6h5h4
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i7i6i5i4m7m6m5m4 j7j6j5j4n7n6n5n4 k7k6k5k4o7o6o5o4 l7l6l5l4p7p6p5p4
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d2,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ move.l a5,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #8,d7
+ eor.l d1,d7
+ and.l d5,d7
+ eor.l d7,d1
+ move.l a6,(a1)+
+ lsl.l #8,d7
+ eor.l d7,d3
+
+ | a7a6a5a4e7e6e5e4 i7i6i5i4m7m6m5m4 c7c6c5c4g7g6g5g4 k7k6k5k4o7o6o5o4
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b7b6b5b4f7f6f5f4 j7j6j5j4n7n6n5n4 d7d6d5d4h7h6h5h4 l7l6l5l4p7p6p5p4
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ cmp.l a1,a7 | end of dst line?
+ bne.s c2p1x1_8_tt_start
+
+ add.l (screen_offset,pc),a1
+ add.l (screen_pitch,pc),a7
+
+c2p1x1_8_tt_start:
+ move.l d2,d7
+ lsr.l #1,d7
+ eor.l d0,d7
+ and.l d6,d7
+ eor.l d7,d0
+ add.l d7,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #1,d7
+ eor.l d1,d7
+ and.l d6,d7
+ eor.l d7,d1
+ add.l d7,d7
+ eor.l d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
+ | a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.w d2,d7
+ move.w d0,d2
+ swap d2
+ move.w d2,d0
+ move.w d7,d2
+ move.w d3,d7
+ move.w d1,d3
+ swap d3
+ move.w d3,d1
+ move.w d7,d3
+
+ | a7b7a5b5e7f7e5f5 i7j7i5j5m7n7m5n5 a6b6a4b4e6f6e4f4 i6j6i4j4m6n6m4n4
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
+ | c7d7c5d5g7h7g5h5 k7l7k5l5o7p7o5p5 c6d6c4d4g6h6g4h4 k6l6k4l4o6p6o4p4
+ | c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.l d2,d7
+ lsr.l #2,d7
+ eor.l d0,d7
+ and.l #0x33333333,d7
+ eor.l d7,d0
+ lsl.l #2,d7
+ eor.l d7,d2
+ move.l d3,d7
+ lsr.l #2,d7
+ eor.l d1,d7
+ and.l #0x33333333,d7
+ eor.l d7,d1
+ lsl.l #2,d7
+ eor.l d7,d3
+
+ | a7b7c7d7e7f7g7h7 i7j7k7l7m7n7o7p7 a6b6c6d6e6f6g6h6 i6j6k6l6m6n6o6p6
+ | a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
+ | a5b5c5d5e5f5g5h5 i5j5k5l5m5n5o5p5 a4b4c4d4e4f4g4h4 i4j4k4l4m4n4o4p4
+ | a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
+
+ swap d0
+ swap d1
+ swap d2
+ swap d3
+
+ move.l d0,a6
+ move.l d2,a5
+ move.l d1,a4
+ move.l d3,a3
+
+ cmp.l a0,a2
+ bne c2p1x1_8_tt_pix16
+
+ move.l a3,(a1)+
+ move.l a4,(a1)+
+ move.l a5,(a1)+
+ move.l a6,(a1)+
+
+ move.l old_sp,sp
+ movem.l (sp)+,d2-d7/a2-a6
+ rts
+
+
| void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
_asm_c2p1x1_8_rect:
movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
@@ -456,6 +674,253 @@ c2p1x1_8_rect_done:
movem.l (sp)+,d2-d7/a2-a6
rts
+
+| void asm_c2p1x1_4(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
+_asm_c2p1x1_4:
+ move.l (4,sp),a0 | chunky
+ move.l (8,sp),d0 | chunky end
+ move.l (12,sp),a1 | screen
+ movem.l d2-d7/a2-a6,-(sp)
+ move.l d0,a2
+ move.l #0x0f0f0f0f,d4
+ move.l #0x00ff00ff,d5
+ move.l #0x55555555,d6
+
+ move.l (a0)+,d0
+ move.l (a0)+,d2
+ move.l (a0)+,d1
+ move.l (a0)+,d3
+ and.l d4,d0
+ and.l d4,d2
+ and.l d4,d1
+ and.l d4,d3
+ lsl.l #4,d0
+ lsl.l #4,d1
+ or.l d2,d0
+ or.l d3,d1
+ bra.s c2p1x1_4_start
+
+c2p1x1_4_pix16:
+ move.l (a0)+,d0
+ move.l (a0)+,d2
+ move.l (a0)+,d1
+ move.l (a0)+,d3
+ and.l d4,d0
+ and.l d4,d2
+ move.l a5,(a1)+
+ and.l d4,d1
+ and.l d4,d3
+ move.l a6,(a1)+
+ lsl.l #4,d0
+ lsl.l #4,d1
+ or.l d2,d0
+ or.l d3,d1
+
+c2p1x1_4_start:
+
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ lsl.l #8,d7
+ eor.l d7,d1
+
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #1,d7
+ eor.l d0,d7
+ and.l d6,d7
+ eor.l d7,d0
+ add.l d7,d7
+ eor.l d7,d1
+
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
+ | a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.w d1,d7
+ move.w d0,d1
+ swap d1
+ move.w d1,d0
+ move.w d7,d1
+
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
+ | c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.l d1,d7
+ lsr.l #2,d7
+ eor.l d0,d7
+ and.l #0x33333333,d7
+ eor.l d7,d0
+ lsl.l #2,d7
+ eor.l d7,d1
+
+ | a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
+ | a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
+
+ swap d0
+ swap d1
+
+ move.l d1,a5
+ move.l d0,a6
+
+ cmp.l a0,a2
+ bne.s c2p1x1_4_pix16
+
+ move.l a5,(a1)+
+ move.l a6,(a1)+
+
+ movem.l (sp)+,d2-d7/a2-a6
+ rts
+
+
+| void asm_c2p1x1_4_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
+_asm_c2p1x1_4_rect:
+ movem.l d2-d7/a2-a6,-(sp) | 6 + 5 = 11 longs
+
+ 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 sp,old_sp
+
+ 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
+
+ move.l d1,screen_pitch
+
+ sub.l d3,d1
+ move.l d1,screen_offset
+
+ move.l d2,chunky_pitch
+
+ sub.l d0,d2
+ move.l d2,chunky_offset
+
+ move.l #0x0f0f0f0f,d4
+ move.l #0x00ff00ff,d5
+ move.l #0x55555555,d6
+
+ move.l (a0)+,d0
+ move.l (a0)+,d2
+ move.l (a0)+,d1
+ move.l (a0)+,d3
+ and.l d4,d0
+ and.l d4,d2
+ and.l d4,d1
+ and.l d4,d3
+ lsl.l #4,d0
+ lsl.l #4,d1
+ or.l d2,d0
+ or.l d3,d1
+ bra.s c2p1x1_4_rect_start
+
+c2p1x1_4_rect_pix16:
+ move.l (a0)+,d0
+ move.l (a0)+,d2
+ move.l (a0)+,d1
+ move.l (a0)+,d3
+ and.l d4,d0
+ and.l d4,d2
+ move.l a5,(a1)+
+ and.l d4,d1
+ and.l d4,d3
+ move.l a6,(a1)+
+ lsl.l #4,d0
+ lsl.l #4,d1
+ or.l d2,d0
+ or.l d3,d1
+
+ cmp.l a1,a7 | end of dst line?
+ bne.s c2p1x1_4_rect_start
+
+ add.l (screen_offset,pc),a1
+ add.l (screen_pitch,pc),a7
+
+c2p1x1_4_rect_start:
+
+ | a3a2a1a0e3e2e1e0 b3b2b1b0f3f2f1f0 c3c2c1c0g3g2g1g0 d3d2d1d0h3h2h1h0
+ | i3i2i1i0m3m2m1m0 j3j2j1j0n3n2n1n0 k3k2k1k0o3o2o1o0 l3l2l1l0p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #8,d7
+ eor.l d0,d7
+ and.l d5,d7
+ eor.l d7,d0
+ lsl.l #8,d7
+ eor.l d7,d1
+
+ | a3a2a1a0e3e2e1e0 i3i2i1i0m3m2m1m0 c3c2c1c0g3g2g1g0 k3k2k1k0o3o2o1o0
+ | b3b2b1b0f3f2f1f0 j3j2j1j0n3n2n1n0 d3d2d1d0h3h2h1h0 l3l2l1l0p3p2p1p0
+
+ move.l d1,d7
+ lsr.l #1,d7
+ eor.l d0,d7
+ and.l d6,d7
+ eor.l d7,d0
+ add.l d7,d7
+ eor.l d7,d1
+
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1
+ | a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.w d1,d7
+ move.w d0,d1
+ swap d1
+ move.w d1,d0
+ move.w d7,d1
+
+ | a3b3a1b1e3f3e1f1 i3j3i1j1m3n3m1n1 a2b2a0b0e2f2e0f0 i2j2i0j0m2n2m0n0
+ | c3d3c1d1g3h3g1h1 k3l3k1l1o3p3o1p1 c2d2c0d0g2h2g0h0 k2l2k0l0o2p2o0p0
+
+ move.l d1,d7
+ lsr.l #2,d7
+ eor.l d0,d7
+ and.l #0x33333333,d7
+ eor.l d7,d0
+ lsl.l #2,d7
+ eor.l d7,d1
+
+ | a3b3c3d3e3f3g3h3 i3j3k3l3m3n3o3p3 a2b2c2d2e2f2g2h2 i2j2k2l2m2n2o2p2
+ | a1b1c1d1e1f1g1h1 i1j1k1l1m1n1o1p1 a0b0c0d0e0f0g0h0 i0j0k0l0m0n0o0p0
+
+ swap d0
+ swap d1
+
+ move.l d1,a5
+ move.l d0,a6
+
+ cmp.l a0,a2 | end of src line?
+ bne c2p1x1_4_rect_pix16
+
+ cmp.l (chunky_end,pc),a2
+ beq.s c2p1x1_4_rect_done
+
+ add.l (chunky_offset,pc),a0
+ add.l (chunky_pitch,pc),a2
+
+ bra c2p1x1_4_rect_pix16
+
+c2p1x1_4_rect_done:
+ move.l a5,(a1)+
+ move.l a6,(a1)+
+
+ move.l old_sp,sp
+ movem.l (sp)+,d2-d7/a2-a6
+ rts
+
+
| place it within reach of 32K (PC relative)
screen_pitch:
ds.l 1
diff --git a/backends/graphics/atari/atari_c2p-asm.h b/backends/graphics/atari/atari_c2p-asm.h
index 66129f8cb7a..6783da89642 100644
--- a/backends/graphics/atari/atari_c2p-asm.h
+++ b/backends/graphics/atari/atari_c2p-asm.h
@@ -31,11 +31,22 @@ extern "C" {
* Optimized for surface-to-surface copy with the same pitch.
*
* @param pChunky chunky buffer start
- * @param pChunkyEnd chunky buffer end (including the last byte)
+ * @param pChunkyEnd chunky buffer end (past-the-end iterator)
* @param pScreen bitplane screen start
*/
void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
+/**
+ * Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
+ * Optimized for surface-to-surface copy with the double screen pitch (typically 320x480).
+ *
+ * @param pChunky chunky buffer start
+ * @param pChunkyEnd chunky buffer end (past-the-end iterator)
+ * @param pScreen bitplane screen start
+ * @param screenPitch bitplane screen width (in bytes)
+ */
+void asm_c2p1x1_8_tt(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen, uint32 screenPitch);
+
/**
* Chunky to planar conversion routine. Converts a chunky (byte) buffer into eight bitplanes.
* Optimized for arbitrary rectangle position and dimension (16px aligned).
@@ -49,6 +60,29 @@ void asm_c2p1x1_8(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
*/
void asm_c2p1x1_8_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
+/**
+ * Chunky to planar conversion routine. Converts a chunky (byte) buffer into four bitplanes.
+ * Optimized for surface-to-surface copy with the same pitch.
+ *
+ * @param pChunky chunky buffer start
+ * @param pChunkyEnd chunky buffer end (past-the-end iterator)
+ * @param pScreen bitplane screen start
+ */
+void asm_c2p1x1_4(const byte *pChunky, const byte *pChunkyEnd, byte *pScreen);
+
+/**
+ * Chunky to planar conversion routine. Converts a chunky (byte) buffer into four bitplanes.
+ * Optimized for arbitrary rectangle position and dimension (16px aligned).
+ *
+ * @param pChunky chunky buffer at rectangle's [X1, Y1] position
+ * @param pChunkyEnd chunky buffer at rectangle's [X2, Y2] position (included)
+ * @param chunkyWidth rectangle width
+ * @param chunkyPitch chunky buffer width (in bytes)
+ * @param pScreen bitplane screen at rectangle's [X1, Y1] position
+ * @param screenPitch bitplane screen width (in bytes)
+ */
+void asm_c2p1x1_4_rect(const byte *pChunky, const byte *pChunkyEnd, uint32 chunkyWidth, uint32 chunkyPitch, byte *pScreen, uint32 screenPitch);
+
}
#endif
diff --git a/backends/graphics/atari/videl-resolutions.cpp b/backends/graphics/atari/videl-resolutions.cpp
deleted file mode 100644
index e676a174747..00000000000
--- a/backends/graphics/atari/videl-resolutions.cpp
+++ /dev/null
@@ -1,194 +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/>.
- *
- */
-
-#include "backends/graphics/atari/videl-resolutions.h"
-
-#include "common/scummsys.h"
-
-const byte scp_320x200x8_rgb[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc2, 0x8c, 0xb0,
- 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40,
- 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xfe, 0x00, 0x99, 0x00, 0x59, 0x00, 0x26, 0x00, 0x87,
- 0x00, 0xd9, 0x02, 0x71, 0x02, 0x11, 0x00, 0x81, 0x00, 0x81, 0x02, 0x11,
- 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0xa0
-};
-
-const byte scp_320x200x8_rgb60[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa7, 0xd8, 0xc0, 0x00, 0xc4, 0x74, 0xf8,
- 0x01, 0x60, 0x05, 0x00, 0x02, 0x54, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x08, 0xc0, 0x00, 0x00, 0x06, 0xc0, 0x00, 0x23,
- 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xfe, 0x00, 0x98, 0x00, 0x58, 0x00, 0x25, 0x00, 0x86,
- 0x00, 0xd9, 0x02, 0x0d, 0x01, 0xd7, 0x00, 0x47, 0x00, 0x47, 0x01, 0xd7,
- 0x02, 0x07, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0xa0
-};
-
-byte scp_320x200x8_vga[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x19, 0x74, 0x90, 0x00, 0x46, 0x4e, 0x20,
- 0x00, 0x2a, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x00, 0x08, 0x7a, 0x00, 0x00, 0x06, 0x8a, 0x00, 0x46,
- 0x01, 0x90, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8d, 0x00, 0x15, 0x02, 0x9a, 0x00, 0x7b,
- 0x00, 0x97, 0x04, 0x19, 0x03, 0xad, 0x00, 0x8d, 0x00, 0x8d, 0x03, 0xad,
- 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05,
- 0x00, 0xa0
-};
-
-const byte scp_320x240x8_rgb[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x33, 0x32, 0x30, 0x2a,
- 0x32, 0x30, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
- 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x35, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
- 0x2c, 0x20, 0x31, 0x35, 0x36, 0x32, 0x35, 0x20, 0x48, 0x7a, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xa9, 0xc1, 0x08, 0x00, 0xc2, 0x8c, 0xb0,
- 0x01, 0x64, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x2c,
- 0x00, 0xf0, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xfe, 0x00, 0x99, 0x00, 0x59, 0x00, 0x26, 0x00, 0x87,
- 0x00, 0xd9, 0x02, 0x71, 0x02, 0x39, 0x00, 0x59, 0x00, 0x59, 0x02, 0x39,
- 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0xa0
-};
-
-byte scp_320x240x8_vga[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x19, 0x74, 0x90, 0x00, 0x46, 0x4e, 0x20,
- 0x00, 0x2a, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0x93, 0x00, 0x1f,
- 0x01, 0xe0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8d, 0x00, 0x15, 0x02, 0x9a, 0x00, 0x7b,
- 0x00, 0x97, 0x04, 0x19, 0x03, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x03, 0xff,
- 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x05,
- 0x00, 0xa0
-};
-
-const byte scp_640x400x8_rgb[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xab, 0xa9, 0x50, 0x00, 0xc1, 0x98, 0x8c,
- 0x01, 0x68, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x40,
- 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0xfe, 0x01, 0x34, 0x00, 0xb4, 0x00, 0x71, 0x01, 0x22,
- 0x01, 0xb3, 0x02, 0x70, 0x02, 0x11, 0x00, 0x81, 0x00, 0x80, 0x02, 0x10,
- 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
- 0x01, 0x40
-};
-
-const byte scp_640x400x8_rgb60[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x47, 0x86, 0x8c, 0x00, 0xb1, 0x62, 0x28, 0x00, 0xbd, 0xc7, 0xfc,
- 0x01, 0x74, 0x05, 0x00, 0x02, 0x53, 0x00, 0x00, 0x3c, 0xea, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x09, 0x40, 0x00, 0x00, 0x06, 0x40, 0x00, 0x25,
- 0x00, 0xc8, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0xff, 0x01, 0x39, 0x00, 0xba, 0x00, 0x77, 0x01, 0x27,
- 0x01, 0xb5, 0x02, 0x0c, 0x01, 0xdb, 0x00, 0x4b, 0x00, 0x4a, 0x01, 0xda,
- 0x02, 0x07, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
- 0x01, 0x40
-};
-
-byte scp_640x400x8_vga[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x36, 0x34, 0x30, 0x2a,
- 0x34, 0x38, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
- 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x36, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
- 0x2c, 0x20, 0x33, 0x31, 0x34, 0x37, 0x30, 0x20, 0x48, 0x7a, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x1a, 0xaa, 0xe0, 0x00, 0x45, 0x17, 0xd0,
- 0x00, 0x2c, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x00, 0x08, 0x99, 0x00, 0x00, 0x06, 0x6b, 0x00, 0x47,
- 0x01, 0x90, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8e, 0x00, 0x16, 0x02, 0xac, 0x00, 0x85,
- 0x00, 0x97, 0x04, 0x19, 0x03, 0xaf, 0x00, 0x8f, 0x00, 0x8f, 0x03, 0xaf,
- 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08,
- 0x01, 0x40
-};
-
-const byte scp_640x480x8_rgb[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x01, 0x36, 0x34, 0x30, 0x2a,
- 0x34, 0x30, 0x30, 0x2c, 0x20, 0x32, 0x35, 0x36, 0x20, 0x46, 0x61, 0x72,
- 0x62, 0x65, 0x6e, 0x2c, 0x20, 0x35, 0x30, 0x2e, 0x30, 0x20, 0x48, 0x7a,
- 0x20, 0x28, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6c, 0x2e, 0x29, 0x2c, 0x20,
- 0x31, 0x35, 0x36, 0x32, 0x35, 0x20, 0x48, 0x7a, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x48, 0x7a, 0xb0, 0x00, 0xab, 0xa9, 0x50, 0x00, 0xc1, 0x98, 0x8c,
- 0x01, 0x68, 0x05, 0x00, 0x01, 0xf4, 0x00, 0x00, 0x3d, 0x09, 0x00, 0x00,
- 0x00, 0xc0, 0x00, 0x00, 0x0a, 0xc0, 0x00, 0x00, 0x07, 0x40, 0x00, 0x2b,
- 0x00, 0xf0, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0xfe, 0x01, 0x34, 0x00, 0xb4, 0x00, 0x71, 0x01, 0x22,
- 0x01, 0xb3, 0x02, 0x70, 0x02, 0x37, 0x00, 0x57, 0x00, 0x56, 0x02, 0x36,
- 0x02, 0x6b, 0x02, 0x00, 0x01, 0x81, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06,
- 0x01, 0x40
-};
-
-byte scp_640x480x8_vga[] = {
- 0x53, 0x43, 0x50, 0x4e, 0x00, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x3a, 0x2f, 0x00, 0x00, 0x1a, 0xaa, 0xe0, 0x00, 0x45, 0x17, 0xd0,
- 0x00, 0x2c, 0x02, 0x80, 0x02, 0x58, 0x00, 0x00, 0x7a, 0xee, 0x00, 0x00,
- 0x00, 0x3e, 0x00, 0x00, 0x03, 0xc1, 0x00, 0x00, 0x01, 0x93, 0x00, 0x1f,
- 0x01, 0xe0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x01, 0xe8, 0x48, 0x00,
- 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xc6, 0x00, 0x8e, 0x00, 0x16, 0x02, 0xac, 0x00, 0x85,
- 0x00, 0x97, 0x04, 0x19, 0x03, 0xff, 0x00, 0x3f, 0x00, 0x3f, 0x03, 0xff,
- 0x04, 0x15, 0x02, 0x00, 0x01, 0x86, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08,
- 0x01, 0x40
-};
diff --git a/backends/graphics/atari/videl-resolutions.h b/backends/graphics/atari/videl-resolutions.h
deleted file mode 100644
index d67d8b42b2e..00000000000
--- a/backends/graphics/atari/videl-resolutions.h
+++ /dev/null
@@ -1,43 +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_RESOLUTIONS_H
-#define BACKENDS_GRAPHICS_ATARI_VIDEL_RESOLUTIONS_H
-
-#include "common/scummsys.h"
-
-constexpr int SCP_SIZE = 158;
-
-extern const byte scp_320x200x8_rgb[SCP_SIZE];
-extern const byte scp_320x200x8_rgb60[SCP_SIZE];
-extern byte scp_320x200x8_vga[SCP_SIZE];
-
-extern const byte scp_320x240x8_rgb[SCP_SIZE];
-extern byte scp_320x240x8_vga[SCP_SIZE];
-
-extern const byte scp_640x400x8_rgb[SCP_SIZE];
-extern const byte scp_640x400x8_rgb60[SCP_SIZE];
-extern byte scp_640x400x8_vga[SCP_SIZE];
-
-extern const byte scp_640x480x8_rgb[SCP_SIZE];
-extern byte scp_640x480x8_vga[SCP_SIZE];
-
-#endif
diff --git a/backends/mixer/atari/atari-mixer.cpp b/backends/mixer/atari/atari-mixer.cpp
index 54074f652bb..7eede5566e2 100644
--- a/backends/mixer/atari/atari-mixer.cpp
+++ b/backends/mixer/atari/atari-mixer.cpp
@@ -22,126 +22,197 @@
#include "backends/mixer/atari/atari-mixer.h"
#include <math.h>
-
+#include <mint/cookie.h>
#include <mint/falcon.h>
+#include <mint/osbind.h>
+#include <mint/ostruct.h>
#include "common/config-manager.h"
#include "common/debug.h"
#define DEFAULT_OUTPUT_RATE 24585
+static bool s_audioNotAvailable = true;
+
+void AtariAudioShutdown() {
+ if (!s_audioNotAvailable) {
+ Buffoper(0x00);
+ Sndstatus(SND_RESET);
+ Unlocksnd();
+ }
+}
+
AtariMixerManager::AtariMixerManager() : MixerManager() {
+ debug("AtariMixerManager()");
+
+ _audioSuspended = true;
+
ConfMan.registerDefault("output_rate", DEFAULT_OUTPUT_RATE);
_outputRate = ConfMan.getInt("output_rate");
if (_outputRate <= 0)
_outputRate = DEFAULT_OUTPUT_RATE;
- int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8;
- diff50 = abs(49170 - (int)_outputRate);
- diff33 = abs(32780 - (int)_outputRate);
- diff25 = abs(24585 - (int)_outputRate);
- diff20 = abs(19668 - (int)_outputRate);
- diff16 = abs(16390 - (int)_outputRate);
- diff12 = abs(12292 - (int)_outputRate);
- diff10 = abs(9834 - (int)_outputRate);
- diff8 = abs(8195 - (int)_outputRate);
-
- if (diff50 < diff33) {
- _outputRate = 49170;
- _clk = CLK50K;
- } else if (diff33 < diff25) {
- _outputRate = 32780;
- _clk = CLK33K;
- } else if (diff25 < diff20) {
- _outputRate = 24585;
- _clk = CLK25K;
- } else if (diff20 < diff16) {
- _outputRate = 19668;
- _clk = CLK20K;
- } else if (diff16 < diff12) {
- _outputRate = 16390;
- _clk = CLK16K;
- } else if (diff12 < diff10) {
- _outputRate = 12292;
- _clk = CLK12K;
- } else if (diff10 < diff8) {
- _outputRate = 9834;
- _clk = CLK10K;
- } else {
- _outputRate = 8195;
- _clk = CLK8K;
- }
+ g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
+}
- ConfMan.setInt("output_rate", _outputRate);
- debug("setting %d Hz mixing frequency", _outputRate);
+AtariMixerManager::~AtariMixerManager() {
+ debug("~AtariMixerManager()");
- _samples = 8192;
- while (_samples * 16 > _outputRate * 2)
- _samples >>= 1;
+ g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
- ConfMan.registerDefault("audio_buffer_size", (int)_samples);
+ if (s_audioNotAvailable)
+ return;
- int samples = ConfMan.getInt("audio_buffer_size");
- if (samples > 0)
- _samples = samples;
+ AtariAudioShutdown();
- ConfMan.setInt("audio_buffer_size", (int)_samples);
- debug("sample buffer size: %d", _samples);
+ Mfree(_atariSampleBuffer);
+ _atariSampleBuffer = _atariPhysicalSampleBuffer = _atariLogicalSampleBuffer = nullptr;
- ConfMan.flushToDisk();
+ delete[] _samplesBuf;
+}
- _samplesBuf = new uint8[_samples * 4];
+void AtariMixerManager::init() {
+ long cookie;
+ bool useDevconnectReturnValue = false;
- g_system->getEventManager()->getEventDispatcher()->registerObserver(this, 10, false);
-}
+ if (Getcookie(C__SND, &cookie) == C_FOUND) {
+ if (cookie & SND_16BIT)
+ s_audioNotAvailable = false;
-AtariMixerManager::~AtariMixerManager() {
- g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
+ useDevconnectReturnValue = (cookie & SND_EXT) != 0;
+ }
- Buffoper(0x00);
+ if (s_audioNotAvailable) {
+ warning("Mixer manager requires 16-bit stereo mode, disabling");
+ } else {
+ int clk;
+
+ if (Locksnd() < 0)
+ error("Sound system is locked");
+
+ // try XBIOS APIs which do not set SND_EXT in _SND
+ useDevconnectReturnValue |= (Getcookie(C_STFA, &cookie) == C_FOUND); // STFA
+ useDevconnectReturnValue |= (Getcookie(C_McSn, &cookie) == C_FOUND); // X-SOUND, MacSound
+
+ // reset connection matrix (and other settings)
+ Sndstatus(SND_RESET);
+
+ int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8, diff6;
+ diff50 = abs(49170 - (int)_outputRate);
+ diff33 = abs(32780 - (int)_outputRate);
+ diff25 = abs(24585 - (int)_outputRate);
+ diff20 = abs(19668 - (int)_outputRate);
+ diff16 = abs(16390 - (int)_outputRate);
+ diff12 = abs(12292 - (int)_outputRate);
+ diff10 = abs(9834 - (int)_outputRate);
+ diff8 = abs(8195 - (int)_outputRate);
+
+ if (diff50 < diff33) {
+ _outputRate = 49170;
+ clk = CLK50K;
+ } else if (diff33 < diff25) {
+ _outputRate = 32780;
+ clk = CLK33K;
+ } else if (diff25 < diff20) {
+ _outputRate = 24585;
+ clk = CLK25K;
+ } else if (diff20 < diff16) {
+ _outputRate = 19668;
+ clk = CLK20K;
+ } else if (diff16 < diff12) {
+ _outputRate = 16390;
+ clk = CLK16K;
+ } else if (diff12 < diff10) {
+ _outputRate = 12292;
+ clk = CLK12K;
+ } else if (diff10 < diff8) {
+ _outputRate = 9834;
+ clk = CLK10K;
+ } else {
+ _outputRate = 8195;
+ clk = CLK8K;
+ }
- Mfree(_atariSampleBuffer);
- _atariSampleBuffer = _atariPhysicalSampleBuffer = _atariLogicalSampleBuffer = nullptr;
+ // first try to use Devconnect() with a Falcon prescaler
+ if (Devconnect(DMAPLAY, DAC, CLK25M, clk, NO_SHAKE) != 0) {
+ // the return value is broken on Falcon
+ if (useDevconnectReturnValue) {
+ if (Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, NO_SHAKE) == 0) {
+ // calculate compatible prescaler
+ diff50 = abs(50066 - (int)_outputRate);
+ diff25 = abs(25033 - (int)_outputRate);
+ diff12 = abs(12517 - (int)_outputRate);
+ diff6 = abs(6258 - (int)_outputRate);
+
+ if (diff50 < diff25) {
+ _outputRate = 50066;
+ clk = PRE160;
+ } else if (diff25 < diff12) {
+ _outputRate = 25033;
+ clk = PRE320;
+ } else if (diff12 < diff6) {
+ _outputRate = 12517;
+ clk = PRE640;
+ } else {
+ _outputRate = 6258;
+ clk = PRE1280;
+ }
+
+ Soundcmd(SETPRESCALE, clk);
+ } else {
+ error("Devconnect() failed");
+ }
+ }
+ }
- Sndstatus(SND_RESET);
+ ConfMan.setInt("output_rate", _outputRate);
+ debug("setting %d Hz mixing frequency", _outputRate);
- Unlocksnd();
+ _samples = 8192;
+ while (_samples * 16 > _outputRate * 2)
+ _samples >>= 1;
- _atariInitialized = false;
+ ConfMan.registerDefault("audio_buffer_size", (int)_samples);
- delete[] _samplesBuf;
-}
+ int samples = ConfMan.getInt("audio_buffer_size");
+ if (samples > 0)
+ _samples = samples;
-void AtariMixerManager::init() {
- _mixer = new Audio::MixerImpl(_outputRate, _samples);
- _mixer->setReady(true);
+ ConfMan.setInt("audio_buffer_size", (int)_samples);
+ debug("sample buffer size: %d", _samples);
- _atariSampleBufferSize = _samples * 4;
+ ConfMan.flushToDisk();
- _atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
- if (!_atariSampleBuffer)
- return;
+ _atariSampleBufferSize = _samples * 4;
- _atariPhysicalSampleBuffer = _atariSampleBuffer;
- _atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
+ _atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
+ if (!_atariSampleBuffer)
+ error("Failed to allocate memory in ST RAM");
- memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
+ _atariPhysicalSampleBuffer = _atariSampleBuffer;
+ _atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
- if (Locksnd() < 0)
- return;
+ memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
- Sndstatus(SND_RESET);
- Setmode(MODE_STEREO16);
- Devconnect(DMAPLAY, DAC, CLK25M, _clk, NO_SHAKE);
- Soundcmd(ADDERIN, MATIN);
- Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
- Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+ Setmode(MODE_STEREO16);
+ Soundcmd(ADDERIN, MATIN);
+ Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
+ Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+
+ _samplesBuf = new uint8[_samples * 4];
+ }
+
+ _mixer = new Audio::MixerImpl(_outputRate, _samples);
+ _mixer->setReady(true);
- _atariInitialized = true;
+ _audioSuspended = false;
}
void AtariMixerManager::suspendAudio() {
+ if (s_audioNotAvailable)
+ return;
+
debug("suspendAudio");
Buffoper(0x00);
@@ -150,13 +221,10 @@ void AtariMixerManager::suspendAudio() {
}
int AtariMixerManager::resumeAudio() {
- debug("resumeAudio 1");
+ if (s_audioNotAvailable)
+ return 0;
- if (!_audioSuspended || !_atariInitialized) {
- return -2;
- }
-
- debug("resumeAudio 2");
+ debug("resumeAudio");
Buffoper(SB_PLA_ENA | SB_PLA_RPT);
@@ -165,10 +233,13 @@ int AtariMixerManager::resumeAudio() {
}
bool AtariMixerManager::notifyEvent(const Common::Event &event) {
+ if (s_audioNotAvailable)
+ return false;
+
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
- debug("silencing the mixer");
+ debug("silencing the mixer"); // TODO: is it for long enough?
memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
return false;
case Common::EVENT_MUTE:
@@ -187,6 +258,12 @@ void AtariMixerManager::update() {
return;
}
+ if (s_audioNotAvailable) {
+ static byte dummy[4];
+ _mixer->mixCallback(dummy, 0);
+ return;
+ }
+
static bool loadSampleFlag = true;
byte *buf = nullptr;
@@ -195,20 +272,18 @@ void AtariMixerManager::update() {
return;
if (!loadSampleFlag) {
- // we play from _atariPhysicalSampleBuffer (1st buffer)
if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
buf = _atariLogicalSampleBuffer;
loadSampleFlag = !loadSampleFlag;
}
} else {
- // we play from _atariLogicalSampleBuffer (2nd buffer)
if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
buf = _atariPhysicalSampleBuffer;
loadSampleFlag = !loadSampleFlag;
}
}
- if (_atariInitialized && buf != nullptr) {
+ if (buf != nullptr) {
assert(_mixer);
// generates stereo 16-bit samples
int processed = _mixer->mixCallback(_samplesBuf, _muted ? 0 : _samples * 4);
diff --git a/backends/mixer/atari/atari-mixer.h b/backends/mixer/atari/atari-mixer.h
index cbbd20a611f..b0f7d233cbe 100644
--- a/backends/mixer/atari/atari-mixer.h
+++ b/backends/mixer/atari/atari-mixer.h
@@ -43,12 +43,10 @@ public:
bool notifyEvent(const Common::Event &event) override;
private:
- int _clk;
uint32 _outputRate;
- uint32 _samples;
- uint8 *_samplesBuf;
+ uint32 _samples = 0;
+ uint8 *_samplesBuf = nullptr;
- bool _atariInitialized = false;
byte *_atariSampleBuffer = nullptr;
byte *_atariPhysicalSampleBuffer = nullptr;
byte *_atariLogicalSampleBuffer = nullptr;
diff --git a/backends/module.mk b/backends/module.mk
index b6885089340..f022bb314bd 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -360,7 +360,6 @@ MODULE_OBJS += \
graphics/atari/atari_c2p-asm.o \
graphics/atari/atari-graphics.o \
graphics/atari/atari-graphics-asm.o \
- graphics/atari/videl-resolutions.o \
mixer/atari/atari-mixer.o
endif
diff --git a/backends/platform/atari/atari_ikbd.S b/backends/platform/atari/atari_ikbd.S
index b5a796611f9..07b51af12f4 100644
--- a/backends/platform/atari/atari_ikbd.S
+++ b/backends/platform/atari/atari_ikbd.S
@@ -19,215 +19,58 @@
*
*/
-/*
- * IKBD 6301 interrupt routine
- *
- * Patrice Mandin
- */
-
- .globl _atari_ikbd_init
- .globl _atari_ikbd_shutdown
-
- .globl _g_atari_ikbd_mouse_buttons_state
- .globl _g_atari_ikbd_mouse_delta_x
- .globl _g_atari_ikbd_mouse_delta_y
+ .global _atari_kbdvec
+ .global _atari_mousevec
+ .global _atari_vkbderr
- .globl _g_atari_ikbd_scancodes
- .globl _g_atari_ikbd_scancodes_size
- .globl _g_atari_ikbb_scancodes_head
+ .extern _g_atari_ikbd_mouse_buttons_state
+ .extern _g_atari_ikbd_mouse_delta_x
+ .extern _g_atari_ikbd_mouse_delta_y
+ .extern _g_atari_ikbd_scancodes
+ .extern _g_atari_ikbd_scancodes_mask
+ .extern _g_atari_ikbb_scancodes_head
.text
-_atari_ikbd_init:
- | Disable interrupts
-
- movew sr,d1
- movew #0x2700,sr
-
- | Save MFP registers used for keyboard
-
- lea 0xfffffa00:w,a0
- btst #6,a0@(0x09)
- sne ikbd_ierb
- btst #6,a0@(0x15)
- sne ikbd_imrb
-
- | Set our routine
-
- movel 0x118:w,old_ikbd
- movel #ikbd,0x118:w
- bset #6,0xfffffa09:w | IERB
- bset #6,0xfffffa15:w | IMRB
-
- | Set mouse relative mode
-
- moveb #8,0xfffffc02:w
-
- | Reenable interrupts
-
- movew d1,sr
- rts
-
-_atari_ikbd_shutdown:
- | Disable interrupts
-
- movew sr,d1
- movew #0x2700,sr
-
- | Restore previous MFP registers
-
- lea 0xfffffa00:w,a0
-
- bclr #6,a0@(0x09)
- tstb ikbd_ierb
- beqs ikbd_restoreierb
- bset #6,a0@(0x09)
-ikbd_restoreierb:
-
- bclr #6,a0@(0x15)
- tstb ikbd_imrb
- beqs ikbd_restoreimrb
- bset #6,a0@(0x15)
-ikbd_restoreimrb:
-
- movel old_ikbd,0x118:w
-
- | Clear keyboard buffer
-
- lea 0xfffffc00:w,a0
-ikbd_videbuffer:
- btst #0,a0@
- beqs ikbd_finbuffer
- tstb a0@(0x02)
- bras ikbd_videbuffer
-ikbd_finbuffer:
-
- | Reenable interrupts
-
- movew d1,sr
- rts
-
- .bss
-
- .even
-ikbd_ierb:
- .ds.b 1
-ikbd_imrb:
- .ds.b 1
+_atari_kbdvec:
+ tst.w (vkbderr_count,pc)
+ bne.b kbdvec_end
-/*--- Our custom IKBD vector ---*/
-
- .text
- .even
- .ascii "XBRA"
- .ascii "SCUM"
-old_ikbd:
- .dc.l 0
-ikbd:
- moveml d0-d1/a0,sp at -
-
- | Check if source is IKBD or MIDI
-
- btst #0,0xfffffc00.w
- beqs ikbd_oldmidi
-
- moveb 0xfffffc02:w,d0
-
- | Not supported packets ?
-
- | status report
- cmpb #0xf6,d0
- beqs ikbd_endit_stack
- | absolute mouse position record
- cmpb #0xf7,d0
- beqs ikbd_endit_stack
- | time-of-day
- cmpb #0xfc,d0
- beqs ikbd_endit_stack
-
- | Joystick packet ?
-
- | joystick report (both sticks), joystick 0 event, joystick 1 event
- cmpb #0xfd,d0
- bhss ikbd_endit_stack
-
- | Mouse packet ?
-
- cmpb #0xf8,d0
- blos ikbd_no_mouse
- cmpb #0xfc,d0
- bhss ikbd_no_mouse
-
- | Mouse packet, byte #1
-
-ikbd_yes_mouse:
- andw #3,d0
- moveb d0,_g_atari_ikbd_mouse_buttons_state
-
- movel #ikbd_mousex,0x118:w
- bras ikbd_endit_stack
-
- | Keyboard press/release
-
-ikbd_no_mouse:
lea _g_atari_ikbd_scancodes,a0
- movew _g_atari_ikbb_scancodes_head,d1
+ move.w _g_atari_ikbb_scancodes_head,d1
| g_atari_ikbd_scancodes[g_atari_ikbb_scancodes_head] = scancode
- moveb d0,(0.b,a0,d1.w)
-
- addql #1,d1
- andw _g_atari_ikbd_scancodes_mask,d1
- movew d1,_g_atari_ikbb_scancodes_head
-
- | End of interrupt
-
-ikbd_endit_stack:
- moveml sp at +,d0-d1/a0
-
- bclr #6,0xfffffa11:w
- rte
-
- | Call old MIDI interrupt
+ move.b d0,(0.b,a0,d1.w)
-ikbd_oldmidi:
- moveml sp at +,d0-d1/a0
+ addq.l #1,d1
+ and.w _g_atari_ikbd_scancodes_mask,d1
+ move.w d1,_g_atari_ikbb_scancodes_head
- movel old_ikbd,sp at -
+kbdvec_end:
rts
- | Mouse packet, byte #2
-ikbd_mousex:
- moveml d0-d1/a0,sp at -
-
- | Check if source is IKBD or MIDI
- btst #0,0xfffffc00.w
- beqs ikbd_oldmidi
-
- moveb 0xfffffc02:w,d0
- extw d0
- addw d0,_g_atari_ikbd_mouse_delta_x
-
- movel #ikbd_mousey,0x118:w
- bras ikbd_endit_stack
-
- | Mouse packet, byte #3
+_atari_vkbderr:
+ addq.w #1,vkbderr_count
+ rts
-ikbd_mousey:
- moveml d0-d1/a0,sp at -
- | Check if source is IKBD or MIDI
+_atari_mousevec:
+ clr.w vkbderr_count
- btst #0,0xfffffc00.w
- beqs ikbd_oldmidi
+ move.b (a0)+,_g_atari_ikbd_mouse_buttons_state
- moveb 0xfffffc02:w,d0
- extw d0
+ move.b (a0)+,d0
+ ext.w d0
+ add.w d0,_g_atari_ikbd_mouse_delta_x
- addw d0,_g_atari_ikbd_mouse_delta_y
+ move.b (a0)+,d0
+ ext.w d0
+ add.w d0,_g_atari_ikbd_mouse_delta_y
+ rts
- movel #ikbd,0x118:w
- bras ikbd_endit_stack
+// place it within reach of 32K (PC relative)
+vkbderr_count:
+ dc.w 0
diff --git a/backends/platform/atari/build-release.sh b/backends/platform/atari/build-release.sh
index d67c57014bc..a40485f66b3 100755
--- a/backends/platform/atari/build-release.sh
+++ b/backends/platform/atari/build-release.sh
@@ -43,7 +43,10 @@ do
unzip -d tmp "$f" && cd tmp && zip -0 ../$(basename "$f") * && cd .. && rm -r tmp && rm "$f"
done
)
+# absent gui-icons.dat massively speeds up startup time (used for the grid mode)
+rm ../data/gui-icons.dat
cd -
# readme.txt
cp ../backends/platform/atari/readme.txt dist-generic/scummvm
+unix2dos dist-generic/scummvm/readme.txt
diff --git a/backends/platform/atari/build-release030.sh b/backends/platform/atari/build-release030.sh
index 90744f31879..d0d9746d0e1 100755
--- a/backends/platform/atari/build-release030.sh
+++ b/backends/platform/atari/build-release030.sh
@@ -28,7 +28,8 @@ then
--disable-bink \
--opengl-mode=none \
--enable-verbose-build \
- --enable-text-console
+ --enable-text-console \
+ --disable-engine=hugo
fi
make -j 16
@@ -36,7 +37,8 @@ rm -rf dist-generic
make dist-generic
# remove themes
-rm -f dist-generic/scummvm/data/*.zip
+rm -f dist-generic/scummvm/data/*.zip dist-generic/scummvm/data/gui-icons.dat
# readme.txt
cp ../backends/platform/atari/readme.txt dist-generic/scummvm
+unix2dos dist-generic/scummvm/readme.txt
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index be1067a3973..9a27b38a3ee 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -22,34 +22,38 @@
#include <stdio.h>
#include <time.h>
+#include <gem.h>
#include <mint/cookie.h>
+#include <mint/falcon.h>
#include <mint/osbind.h>
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
-#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
-#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
#define FORBIDDEN_SYMBOL_EXCEPTION_fputs
-#define FORBIDDEN_SYMBOL_EXCEPTION_exit
-#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
+#define FORBIDDEN_SYMBOL_EXCEPTION_sprintf
+#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
+#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
+#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#include "backends/platform/atari/osystem_atari.h"
#if defined(ATARI)
-#include "backends/graphics/atari/atari-graphics-asm.h"
-#include "backends/keymapper/hardware-input.h"
-#include "backends/mutex/null/null-mutex.h"
-#include "base/main.h"
-#include "backends/saves/default/default-saves.h"
-#include "backends/timer/default/default-timer.h"
+#include "backends/audiocd/default/default-audiocd.h"
+#include "common/config-manager.h"
#include "backends/events/atari/atari-events.h"
#include "backends/events/default/default-events.h"
-#include "backends/mixer/atari/atari-mixer.h"
-#include "backends/graphics/atari/atari-graphics.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"
+#include "backends/mutex/null/null-mutex.h"
+#include "backends/saves/default/default-saves.h"
+#include "backends/timer/default/default-timer.h"
+#include "base/main.h"
#include "gui/debugger.h"
/*
@@ -57,8 +61,9 @@
*/
#include "backends/fs/posix/posix-fs-factory.h"
-extern "C" void atari_ikbd_init();
-extern "C" void atari_ikbd_shutdown();
+extern "C" void atari_kbdvec(void *);
+extern "C" void atari_mousevec(void *);
+extern "C" void atari_vkbderr(void);
extern "C" void atari_200hz_init();
extern "C" void atari_200hz_shutdown();
@@ -67,36 +72,79 @@ extern "C" volatile uint32 counter_200hz;
extern void nf_init(void);
extern void nf_print(const char* msg);
-OSystem_Atari::OSystem_Atari() {
- _fsFactory = new POSIXFilesystemFactory();
-}
+static int s_app_id = -1;
+static int16 s_vdi_handle;
+static int s_vdi_width, s_vdi_height;
-OSystem_Atari::~OSystem_Atari() {
- debug("OSystem_Atari::~OSystem_Atari()");
+static bool s_tt = false;
+typedef void (*KBDVEC)(void *);
+static KBDVEC s_kbdvec = nullptr;
+static void (*s_vkbderr)(void) = nullptr;
+static KBDVEC s_mousevec = nullptr;
- if (_video_initialized) {
- Supexec(asm_screen_falcon_restore);
- _video_initialized = false;
- }
+static void (*s_old_procterm)(void) = nullptr;
- if (_200hz_initialized) {
- Supexec(atari_200hz_shutdown);
- _200hz_initialized = false;
- }
+static void exit_gem() {
+ if (s_app_id != -1) {
+ //wind_update(END_UPDATE);
+
+ // redraw screen
+ form_dial(FMD_FINISH, 0, 0, 0, 0, 0, 0, s_vdi_width, s_vdi_height);
+ graf_mouse(M_ON, NULL);
- if (_ikbd_initialized) {
- Supexec(atari_ikbd_shutdown);
- _ikbd_initialized = false;
+ v_clsvwk(s_vdi_handle);
+ appl_exit();
}
}
static void critical_restore() {
- Supexec(asm_screen_falcon_restore);
+ extern void AtariAudioShutdown();
+ extern void AtariGraphicsShutdown();
+
+ AtariAudioShutdown();
+ AtariGraphicsShutdown();
+
+ if (s_tt)
+ Supexec(asm_screen_tt_restore);
+ else
+ Supexec(asm_screen_falcon_restore);
Supexec(atari_200hz_shutdown);
- Supexec(atari_ikbd_shutdown);
+
+ if (s_kbdvec && s_vkbderr && s_mousevec) {
+ _KBDVECS *kbdvecs = Kbdvbase();
+ ((uintptr *)kbdvecs)[-1] = (uintptr)s_kbdvec;
+ kbdvecs->vkbderr = s_vkbderr;
+ kbdvecs->mousevec = s_mousevec;
+ s_kbdvec = s_mousevec = nullptr;
+ }
+
+ exit_gem();
}
-void OSystem_Atari::initBackend() {
+OSystem_Atari::OSystem_Atari() {
+ _fsFactory = new POSIXFilesystemFactory();
+
+ nf_init();
+
+ enum {
+ VDO_NO_ATARI_HW = 0xffff,
+ VDO_ST = 0,
+ VDO_STE,
+ VDO_TT,
+ VDO_FALCON,
+ VDO_MILAN
+ };
+
+ long vdo = VDO_NO_ATARI_HW<<16;
+ Getcookie(C__VDO, &vdo);
+ vdo >>= 16;
+
+ if (vdo != VDO_TT && vdo != VDO_FALCON) {
+ error("ScummVM requires Atari TT/Falcon compatible video");
+ }
+
+ s_tt = (vdo == VDO_TT);
+
enum {
MCH_ST = 0,
MCH_STE,
@@ -110,16 +158,83 @@ void OSystem_Atari::initBackend() {
Getcookie(C__MCH, &mch);
mch >>= 16;
- if (mch != MCH_FALCON && mch != MCH_ARANYM) {
- error("ScummVM works only on Atari Falcon and ARAnyM");
+ if (mch == MCH_ARANYM && Getcookie(C_fVDI, NULL) == C_FOUND) {
+ error("Disable fVDI, ScummVM uses XBIOS video calls");
}
- if (mch == MCH_ARANYM && Getcookie(C_fVDI, NULL) == C_FOUND) {
- error("Disable fVDI, ScummVM accesses Videl directly");
+ _KBDVECS *kbdvecs = Kbdvbase();
+ s_kbdvec = (KBDVEC)(((uintptr *)kbdvecs)[-1]);
+ s_vkbderr = kbdvecs->vkbderr;
+ s_mousevec = kbdvecs->mousevec;
+
+ ((uintptr *)kbdvecs)[-1] = (uintptr)atari_kbdvec;
+ kbdvecs->vkbderr = atari_vkbderr;
+ kbdvecs->mousevec = atari_mousevec;
+
+ Supexec(atari_200hz_init);
+ _timerInitialized = true;
+
+ if (s_tt)
+ Supexec(asm_screen_tt_save);
+ else
+ Supexec(asm_screen_falcon_save);
+
+ _videoInitialized = true;
+
+ s_old_procterm = Setexc(VEC_PROCTERM, -1);
+ (void)Setexc(VEC_PROCTERM, critical_restore);
+}
+
+OSystem_Atari::~OSystem_Atari() {
+ debug("OSystem_Atari::~OSystem_Atari()");
+
+ // _audiocdManager needs to be deleted before _mixerManager to avoid a crash.
+ delete _audiocdManager;
+ _audiocdManager = nullptr;
+
+ delete _mixerManager;
+ _mixerManager = nullptr;
+
+ delete _graphicsManager;
+ _graphicsManager = nullptr;
+
+ delete _eventManager;
+ _eventManager = nullptr;
+
+ delete _savefileManager;
+ _savefileManager = nullptr;
+
+ delete _timerManager;
+ _timerManager = nullptr;
+
+ delete _fsFactory;
+ _fsFactory = nullptr;
+
+ if (_videoInitialized) {
+ if (s_tt)
+ Supexec(asm_screen_tt_restore);
+ else {
+ Supexec(asm_screen_falcon_restore);
+ }
+
+ _videoInitialized = false;
}
- nf_init();
+ if (_timerInitialized) {
+ Supexec(atari_200hz_shutdown);
+ _timerInitialized = false;
+ }
+
+ if (s_kbdvec && s_vkbderr && s_mousevec) {
+ _KBDVECS *kbdvecs = Kbdvbase();
+ ((uintptr *)kbdvecs)[-1] = (uintptr)s_kbdvec;
+ kbdvecs->vkbderr = s_vkbderr;
+ kbdvecs->mousevec = s_mousevec;
+ s_kbdvec = s_mousevec = nullptr;
+ }
+}
+void OSystem_Atari::initBackend() {
_timerManager = new DefaultTimerManager();
_savefileManager = new DefaultSaveFileManager("saves");
@@ -142,17 +257,6 @@ void OSystem_Atari::initBackend() {
// Setup and start mixer
_mixerManager->init();
- Supexec(atari_ikbd_init);
- _ikbd_initialized = true;
-
- Supexec(atari_200hz_init);
- _200hz_initialized = true;
-
- Supexec(asm_screen_falcon_save);
- _video_initialized = true;
-
- (void)Setexc(VEC_PROCTERM, critical_restore);
-
_startTime = counter_200hz;
BaseBackend::initBackend();
@@ -207,7 +311,10 @@ void OSystem_Atari::quit() {
g_system->destroy();
- exit(0);
+ // graceful exit
+ (void)Setexc(VEC_PROCTERM, s_old_procterm);
+
+ exit_gem();
}
void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
@@ -218,10 +325,13 @@ void OSystem_Atari::logMessage(LogMessageType::Type type, const char *message) {
else
output = stderr;
- fputs(message, output);
+ static char str[1024+1];
+ sprintf(str, "[%08d] %s", getMillis(), message);
+
+ fputs(str, output);
fflush(output);
- nf_print(message);
+ nf_print(str);
}
void OSystem_Atari::addSysArchivesToSearchSet(Common::SearchSet &s, int priority) {
@@ -272,12 +382,47 @@ OSystem *OSystem_Atari_create() {
}
int main(int argc, char *argv[]) {
+ s_app_id = appl_init();
+ if (s_app_id != -1) {
+ // get the ID of the current physical screen workstation
+ int16 dummy;
+ s_vdi_handle = graf_handle(&dummy, &dummy, &dummy, &dummy);
+ if (s_vdi_handle < 1) {
+ appl_exit();
+ error("graf_handle() failed");
+ }
+
+ int16 work_in[16] = {};
+ int16 work_out[57] = {};
+
+ // open a virtual screen workstation
+ v_opnvwk(work_in, &s_vdi_handle, work_out);
+
+ if (s_vdi_handle == 0) {
+ appl_exit();
+ error("v_opnvwk() failed");
+ }
+
+ s_vdi_width = work_out[0] + 1;
+ s_vdi_height = work_out[1] + 1;
+
+ graf_mouse(M_OFF, NULL);
+ // see https://github.com/freemint/freemint/issues/312
+ //wind_update(BEG_UPDATE);
+ }
+
g_system = OSystem_Atari_create();
assert(g_system);
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
g_system->destroy();
+
+ // graceful exit
+ (void)Setexc(VEC_PROCTERM, s_old_procterm);
+
+ exit_gem();
+
return res;
}
diff --git a/backends/platform/atari/osystem_atari.h b/backends/platform/atari/osystem_atari.h
index 619067e4564..d5ea05cc04f 100644
--- a/backends/platform/atari/osystem_atari.h
+++ b/backends/platform/atari/osystem_atari.h
@@ -51,9 +51,8 @@ public:
private:
long _startTime;
- bool _video_initialized = false;
- bool _200hz_initialized = false;
- bool _ikbd_initialized = false;
+ bool _videoInitialized = false;
+ bool _timerInitialized = false;
};
#endif
diff --git a/backends/platform/atari/readme.txt b/backends/platform/atari/readme.txt
index aac310ed96c..4691f1e9355 100644
--- a/backends/platform/atari/readme.txt
+++ b/backends/platform/atari/readme.txt
@@ -13,7 +13,7 @@ Yet another port?
-----------------
Yes, I am aware of the official Atari/FreeMiNT port done by KeithS over the
-years (https://docs.scummvm.org/en/v2.6.1/other_platforms/atari.html). It is
+years (https://docs.scummvm.org/en/v2.7.0/other_platforms/atari.html). It is
even updated every release and put on the official ScummVM website. That port
is basically just a recompiled SDL backend for our platform - that certainly
has some advantages (works in GEM, can be easily compiled for the FireBee etc.)
@@ -41,34 +41,41 @@ his own backend), I decided to do the same and see whether I could do better.
And I could!
+Hardware requirements
+---------------------
+
+This port requires an Atari computer with TT or Falcon compatible video modes.
+Ideally accelerated with at least 4+32 MB of RAM. It runs fine also in Hatari
+and ARAnyM but in case of ARAnyM don't forget to disable fVDI to show Videl
+output.
+
+
Main features
-------------
-- Optimized for the Atari Falcon (ideally with the CT60/CT63/CT60e but for the
-less hungry games even a CT2/DFB at 50 MHz or the AfterBurner040 could be enough).
+- Optimized for the Atari TT/Falcon: ideally the CT60/CT63/CT60e but some games
+ run fine on the AfterBurner040, CT2/DFB at 50 MHz, Speedy at 48 MHz or even less!
- Full support for the SuperVidel, incl. the SuperBlitter (!)
- Removed features found too demanding for our platform; the most visible
change is the exclusion of the 16bpp games (those are mostly hi-res anyway)
- but games in 640x480 at 8bpp work nicely.
+ but games in 640x480 at 8bpp work nicely (Falcon only, unfortunately).
- Direct rendering and single/triple buffering support.
- Custom (and optimal) drawing routines (especially for the cursor).
-- Custom (Super)Videl resolutions for the best possible performance and visual
- experience (320x240 in RGB, chunky modes with SuperVidel, 640x480 at 8bpp for
- the overlay, ...)
+- Tailored video settings for the best possible performance and visual
+ experience (Falcon RGB overscan, chunky modes with the SuperVidel, TT 640x480
+ for the overlay, ...)
- Custom (hardware based) aspect ratio correction (!)
- Support for PC keys (page up, page down, pause, F11/F12, ...) and mouse wheel
(Eiffel/Aranym only)
-This makes such games as The Curse of Monkey Island better playable (on
-SuperVidel nearly always also with CD (WAV) music and speech). Also, AdLib
-emulation works nicely with many games without noticeable slow downs.
+- AdLib emulation works nicely with many games without noticeable slow downs.
Platform-specific features outside the GUI
@@ -81,8 +88,9 @@ Keyboard shortcut "CONTROL+ALT+a": immediate aspect ratio correction on/off
toggle.
"output_rate" in scummvm.ini: sample rate for mixing, can be 49170, 32780,
-24585, 19668, 16390, 12292, 9834, 8195 (the lower the value, the faster the
-mixing but also in worse quality). Default is 24585 Hz (16-bit, stereo).
+24585, 19668, 16390, 12292, 9834, 8195 on the Falcon and 50066, 25033, 12517,
+6258 on the TT (the lower the value, the faster the mixing but also worse
+quality). Default is 24585/25033 Hz (16-bit, stereo).
"audio_buffer_size" in scummvm.ini: number of samples to preload. Default is
2048 which equals to about 83ms of audio lag and seems to be about right for
@@ -118,13 +126,14 @@ Cons:
- screen tearing in most cases
- SuperVidel only: using C2P would be not only suboptimal (every rectangle
- would be C2P'ed instead of just copy and C2P of the final screen) but poses an
- additional problem as C2P requires data aligned on a 16px boundary and
- ScummVM supplies arbitrarily-sized rectangles (this is solvable by custom
- Surface allocation but it's not bullet-proof). In theory I could implement
- direct rendering for the Falcon hicolor (320x240 at 16bpp) but this creates
- another set of issues like when palette would be updated but not the whole
- screen - so some rectangles would be rendered in old palette and some in new.
+ would be C2P'ed instead of multiple copying and just one C2P of the final
+ screen) but poses an additional problem as C2P requires data aligned on a
+ 16px boundary and ScummVM supplies arbitrarily-sized rectangles (this is
+ solvable by custom Surface allocation but it's not bullet-proof). In theory I
+ could implement direct rendering for the Falcon hicolor (320x240 at 16bpp) but
+ this creates another set of issues like when palette would be updated but not
+ the whole screen - so some rectangles would be rendered in old palette and
+ some in new.
SuperBlitter used: sometimes (when ScummVM allocates surface via its create()
function; custom/small buffers originating in the engine code are still copied
@@ -192,8 +201,7 @@ SuperVidel and SuperBlitter
As mentioned, this port uses SuperVidel and its SuperBlitter heavily. That
means that if the SuperVidel is detected, it does the following:
-- patches all 8bpp VGA resolutions to chunky ones, rendering all C2P routines
- useless
+- uses 8bpp chunky resolutions
- patches all surface addresses with OR'ing 0xA0000000, i.e. using SV RAM
instead of slow ST RAM (and even instead of TT RAM for allowing pure
@@ -205,6 +213,17 @@ means that if the SuperVidel is detected, it does the following:
and makes a *huge* difference for 640x480 fullscreen updates.
+Audio mixing
+------------
+
+ScummVM works internally with 16-bit stereo samples. This mode is not available
+on the TT so a substitute solution must be used. This solution is called STFA
+by The Removers: http://removers.free.fr/softs/stfa.php. Install, activate STFA
+BIOS in the CPX, done. Now you have 16-bit DMA available, too but beware, it is
+also quite CPU demanding so very few games can actually make use of it (see the
+chapter about audio performance considerations below).
+
+
Performance considerations/pitfalls
-----------------------------------
@@ -233,11 +252,23 @@ is (by definition) the case of animated intros, especially those in 640x480.
MIDI vs. AdLib vs. sampled music
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-It could seem that sample music replay must be the most demanding one but on the
-contrary! _Always_ choose a CD version of a game (with *.wav tracks) to any
+It could seem that sample music replay must be the most demanding one but on
+the contrary! Always choose a CD version of a game (with *.wav tracks) to any
other version. With one exception: if you have a native MIDI device able to
-replay the given game's MIDI notes (using the STMIDI plugin). MIDI emulation
-(synthesis) can easily eat as much as 50% of all used CPU time.
+replay the given game's MIDI notes (using the STMIDI plugin).
+
+MIDI emulation (synthesis) can easily eat as much as 50% of all used CPU time
+(on the CT60). By default, this port uses the MAME OPL emulation (which is said
+to be fastest but also least accurate) but some engines require the DOSBOX one
+which is even more demanding. By the way, you can put "FM_high_quality=true"
+or "FM_medium_quality=true" into scummvm.ini if you want to experiment with a
+better quality synthesis, otherwise the lowest quality will be used (applies
+for MAME OPL only).
+
+On the TT, in 95% of cases it makes sense to enable music only if you have a
+native MIDI synthesizer (like mt32-pi: https://github.com/dwhinham/mt32-pi);
+STFA is usually slow to mix samples, too => mute it (see below) or don't
+install STFA (same effect).
CD music slows everything down
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -283,18 +314,41 @@ loading time. To speed things up in other cases, the "fat" version is
distributed with repackaged theme files with compression level zero.
+"Slim" vs. "Fat" version
+------------------------
+
+As a further optimisation step, a 030-only version of ScummVM is provided,
+aimed at accelerated TT and Falcon machines with the 68030 CPU. It further
+restricts features but also improves performance:
+
+- compiled with -m68030 => 68030/68882-specific optimisations enabled
+
+- disabled 040+/SuperVidel code => faster code path for blitting
+
+- doesn't support hires (640x480) games => smaller executable size
+
+- overlay is rendered in 16 colours => faster redraw
+
+- overlay during gameplay has no game backround => ever faster redraw
+
+- overlay doesn't support alternative themes => faster loading time
+
+
Known issues
------------
- aspect ratio correction works on RGB only (yet)
-- SuperVidel's DVI output is stretched when in 320x200 or 640x400; I'll wait
- for other people's experiences, maybe only my LCD is so lame.
-
- adding a game in TOS and loading it in FreeMiNT (and vice versa) generates
incompatible paths. Either use only one system or edit scummvm.ini and set
there only relative paths (mintlib bug/limitation).
+- when run on TT, screen contains horizontal black lines. That is due to the
+ fact that TT offers only 320x480 in 256 colours. Possibly fixable by a Timer
+ B interrupt.
+
+- tooltips in overlay are sometimes drawn with corrupted background.
+
- the talkie version of MI1 needs to be merged from two sources: first generate
the DOS version and then additionally also the flac version. Then convert all
*.flac files into *.wav and replace monkey.sof (flac) with monster.sou (DOS).
@@ -306,11 +360,11 @@ Known issues
Future plans
------------
-- aspect ratio correction for VGA/SuperVidel
+- aspect ratio correction for TT/VGA/SuperVidel
- unified file paths in scummvm.ini
-- DSP-based sample mixer
+- DSP-based sample mixer (WAV, FLAC, MP2)
- avoid loading music/speech files (and thus slowing down everything) if muted
@@ -320,24 +374,10 @@ Future plans
- using LDG or Thorsten Otto's sharedlibs: https://tho-otto.de/sharedlibs.php
for game engine plugins to relieve the huge binary size
-- add support for the TT030; this would be easily possible when I rewrite the
- renderer with a more flexible resolution switching
-
-- don't hardcode some of the buffers for cacheing purposes, determine the size
- based on amount of free RAM
-
- true audio CD support via MetaDOS API
- OPL2LPT and Retrowave support (if I manage to purchase it somewhere)
-- engines based on Graphics::Screen don't have to use my chunky buffer (however
- it may be tricky to detect this situation)
-
-- C2P could support 4- and 6-bit depth
-
-- increase file buffer size with setvbuf or by using
- Common::wrapBufferedWriteStream and disabling stdio buffering
-
Closing words
-------------
diff --git a/configure b/configure
index 652b78ed15f..62016fb685f 100755
--- a/configure
+++ b/configure
@@ -3652,13 +3652,15 @@ if test -n "$_host"; then
if test "$_optimizations" = "yes"; then
# --enable-release, --enable-optimizations
append_var CXXFLAGS "-fomit-frame-pointer"
+ append_var CXXFLAGS "-fno-exceptions"
+ append_var CXXFLAGS "-ffast-math"
fi
# auto -> no
if test "$_release_build" = "yes"; then
# --enable-release
append_var DEFINES "-DNDEBUG"
- append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
+ #append_var DEFINES "-DDISABLE_TEXT_CONSOLE"
append_var CXXFLAGS "-I$HOME/gnu-tools/m68000/m68k-atari-mint/sys-root/opt/mintlib-dlmalloc/include"
append_var LDFLAGS "-L$HOME/gnu-tools/m68000/m68k-atari-mint/sys-root/opt/mintlib-dlmalloc/lib/m68020-60"
fi
@@ -3955,10 +3957,11 @@ case $_backend in
;;
atari)
define_in_config_if_yes yes "ATARI"
- append_var DEFINES "-DDISABLE_LAUNCHERDISPLAY_GRID"
- append_var DEFINES "-DDISABLE_SID"
- append_var DEFINES "-DDISABLE_NES_APU"
- #append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var DEFINES "-DDISABLE_LAUNCHERDISPLAY_GRID"
+ append_var DEFINES "-DDISABLE_SID"
+ append_var DEFINES "-DDISABLE_NES_APU"
+ #append_var DEFINES "-DDISABLE_DOSBOX_OPL"
+ append_var LIBS "-lgem"
;;
dc)
append_var INCLUDES '-I$(srcdir)/backends/platform/dc'
diff --git a/graphics/blit-atari.cpp b/graphics/blit-atari.cpp
index 5020082953a..fcdf60b4011 100644
--- a/graphics/blit-atari.cpp
+++ b/graphics/blit-atari.cpp
@@ -119,7 +119,7 @@ void Surface::create(int16 width, int16 height, const PixelFormat &f) {
if (width && height) {
#ifdef USE_SV_BLITTER
- if (hasSuperVidel()) {
+ if (hasSuperVidel() && w >= 64 && h >= 64) {
pixels = (void *)ct60_vmalloc(height * pitch);
if (!pixels)
Commit: 2ce02658eccaaa333847b00f4b803891ebcb3aa6
https://github.com/scummvm/scummvm/commit/2ce02658eccaaa333847b00f4b803891ebcb3aa6
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-06-15T22:57:55+02:00
Commit Message:
BACKENDS: ATARI: DMA playback is not always active
E.g. in the overlay there's no need to steal cycles for playing empty
sample buffer.
Also make STMIDI default audio driver for the slim version.
Changed paths:
backends/mixer/atari/atari-mixer.cpp
backends/mixer/atari/atari-mixer.h
backends/module.mk
backends/platform/atari/osystem_atari.cpp
backends/platform/atari/osystem_atari.h
backends/platform/atari/readme.txt
diff --git a/backends/mixer/atari/atari-mixer.cpp b/backends/mixer/atari/atari-mixer.cpp
index 7eede5566e2..e6a07cc127a 100644
--- a/backends/mixer/atari/atari-mixer.cpp
+++ b/backends/mixer/atari/atari-mixer.cpp
@@ -32,14 +32,10 @@
#define DEFAULT_OUTPUT_RATE 24585
-static bool s_audioNotAvailable = true;
-
void AtariAudioShutdown() {
- if (!s_audioNotAvailable) {
- Buffoper(0x00);
- Sndstatus(SND_RESET);
- Unlocksnd();
- }
+ Buffoper(0x00);
+ Sndstatus(SND_RESET);
+ Unlocksnd();
}
AtariMixerManager::AtariMixerManager() : MixerManager() {
@@ -61,9 +57,6 @@ AtariMixerManager::~AtariMixerManager() {
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
- if (s_audioNotAvailable)
- return;
-
AtariAudioShutdown();
Mfree(_atariSampleBuffer);
@@ -74,134 +67,120 @@ AtariMixerManager::~AtariMixerManager() {
void AtariMixerManager::init() {
long cookie;
- bool useDevconnectReturnValue = false;
-
- if (Getcookie(C__SND, &cookie) == C_FOUND) {
- if (cookie & SND_16BIT)
- s_audioNotAvailable = false;
-
- useDevconnectReturnValue = (cookie & SND_EXT) != 0;
- }
-
- if (s_audioNotAvailable) {
- warning("Mixer manager requires 16-bit stereo mode, disabling");
+ bool useDevconnectReturnValue = Getcookie(C__SND, &cookie) == C_FOUND && (cookie & SND_EXT) != 0;
+
+ int clk;
+
+ if (Locksnd() < 0)
+ error("Sound system is locked");
+
+ // try XBIOS APIs which do not set SND_EXT in _SND
+ useDevconnectReturnValue |= (Getcookie(C_STFA, &cookie) == C_FOUND); // STFA
+ useDevconnectReturnValue |= (Getcookie(C_McSn, &cookie) == C_FOUND); // X-SOUND, MacSound
+
+ // reset connection matrix (and other settings)
+ Sndstatus(SND_RESET);
+
+ int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8, diff6;
+ diff50 = abs(49170 - (int)_outputRate);
+ diff33 = abs(32780 - (int)_outputRate);
+ diff25 = abs(24585 - (int)_outputRate);
+ diff20 = abs(19668 - (int)_outputRate);
+ diff16 = abs(16390 - (int)_outputRate);
+ diff12 = abs(12292 - (int)_outputRate);
+ diff10 = abs(9834 - (int)_outputRate);
+ diff8 = abs(8195 - (int)_outputRate);
+
+ if (diff50 < diff33) {
+ _outputRate = 49170;
+ clk = CLK50K;
+ } else if (diff33 < diff25) {
+ _outputRate = 32780;
+ clk = CLK33K;
+ } else if (diff25 < diff20) {
+ _outputRate = 24585;
+ clk = CLK25K;
+ } else if (diff20 < diff16) {
+ _outputRate = 19668;
+ clk = CLK20K;
+ } else if (diff16 < diff12) {
+ _outputRate = 16390;
+ clk = CLK16K;
+ } else if (diff12 < diff10) {
+ _outputRate = 12292;
+ clk = CLK12K;
+ } else if (diff10 < diff8) {
+ _outputRate = 9834;
+ clk = CLK10K;
} else {
- int clk;
-
- if (Locksnd() < 0)
- error("Sound system is locked");
-
- // try XBIOS APIs which do not set SND_EXT in _SND
- useDevconnectReturnValue |= (Getcookie(C_STFA, &cookie) == C_FOUND); // STFA
- useDevconnectReturnValue |= (Getcookie(C_McSn, &cookie) == C_FOUND); // X-SOUND, MacSound
-
- // reset connection matrix (and other settings)
- Sndstatus(SND_RESET);
-
- int diff50, diff33, diff25, diff20, diff16, diff12, diff10, diff8, diff6;
- diff50 = abs(49170 - (int)_outputRate);
- diff33 = abs(32780 - (int)_outputRate);
- diff25 = abs(24585 - (int)_outputRate);
- diff20 = abs(19668 - (int)_outputRate);
- diff16 = abs(16390 - (int)_outputRate);
- diff12 = abs(12292 - (int)_outputRate);
- diff10 = abs(9834 - (int)_outputRate);
- diff8 = abs(8195 - (int)_outputRate);
-
- if (diff50 < diff33) {
- _outputRate = 49170;
- clk = CLK50K;
- } else if (diff33 < diff25) {
- _outputRate = 32780;
- clk = CLK33K;
- } else if (diff25 < diff20) {
- _outputRate = 24585;
- clk = CLK25K;
- } else if (diff20 < diff16) {
- _outputRate = 19668;
- clk = CLK20K;
- } else if (diff16 < diff12) {
- _outputRate = 16390;
- clk = CLK16K;
- } else if (diff12 < diff10) {
- _outputRate = 12292;
- clk = CLK12K;
- } else if (diff10 < diff8) {
- _outputRate = 9834;
- clk = CLK10K;
- } else {
- _outputRate = 8195;
- clk = CLK8K;
- }
+ _outputRate = 8195;
+ clk = CLK8K;
+ }
- // first try to use Devconnect() with a Falcon prescaler
- if (Devconnect(DMAPLAY, DAC, CLK25M, clk, NO_SHAKE) != 0) {
- // the return value is broken on Falcon
- if (useDevconnectReturnValue) {
- if (Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, NO_SHAKE) == 0) {
- // calculate compatible prescaler
- diff50 = abs(50066 - (int)_outputRate);
- diff25 = abs(25033 - (int)_outputRate);
- diff12 = abs(12517 - (int)_outputRate);
- diff6 = abs(6258 - (int)_outputRate);
-
- if (diff50 < diff25) {
- _outputRate = 50066;
- clk = PRE160;
- } else if (diff25 < diff12) {
- _outputRate = 25033;
- clk = PRE320;
- } else if (diff12 < diff6) {
- _outputRate = 12517;
- clk = PRE640;
- } else {
- _outputRate = 6258;
- clk = PRE1280;
- }
-
- Soundcmd(SETPRESCALE, clk);
+ // first try to use Devconnect() with a Falcon prescaler
+ if (Devconnect(DMAPLAY, DAC, CLK25M, clk, NO_SHAKE) != 0) {
+ // the return value is broken on Falcon
+ if (useDevconnectReturnValue) {
+ if (Devconnect(DMAPLAY, DAC, CLK25M, CLKOLD, NO_SHAKE) == 0) {
+ // calculate compatible prescaler
+ diff50 = abs(50066 - (int)_outputRate);
+ diff25 = abs(25033 - (int)_outputRate);
+ diff12 = abs(12517 - (int)_outputRate);
+ diff6 = abs(6258 - (int)_outputRate);
+
+ if (diff50 < diff25) {
+ _outputRate = 50066;
+ clk = PRE160;
+ } else if (diff25 < diff12) {
+ _outputRate = 25033;
+ clk = PRE320;
+ } else if (diff12 < diff6) {
+ _outputRate = 12517;
+ clk = PRE640;
} else {
- error("Devconnect() failed");
+ _outputRate = 6258;
+ clk = PRE1280;
}
+
+ Soundcmd(SETPRESCALE, clk);
+ } else {
+ error("Devconnect() failed");
}
}
+ }
- ConfMan.setInt("output_rate", _outputRate);
- debug("setting %d Hz mixing frequency", _outputRate);
-
- _samples = 8192;
- while (_samples * 16 > _outputRate * 2)
- _samples >>= 1;
+ ConfMan.setInt("output_rate", _outputRate);
+ debug("setting %d Hz mixing frequency", _outputRate);
- ConfMan.registerDefault("audio_buffer_size", (int)_samples);
+ _samples = 8192;
+ while (_samples * 16 > _outputRate * 2)
+ _samples >>= 1;
- int samples = ConfMan.getInt("audio_buffer_size");
- if (samples > 0)
- _samples = samples;
+ ConfMan.registerDefault("audio_buffer_size", (int)_samples);
- ConfMan.setInt("audio_buffer_size", (int)_samples);
- debug("sample buffer size: %d", _samples);
+ int samples = ConfMan.getInt("audio_buffer_size");
+ if (samples > 0)
+ _samples = samples;
- ConfMan.flushToDisk();
+ ConfMan.setInt("audio_buffer_size", (int)_samples);
+ debug("sample buffer size: %d", _samples);
- _atariSampleBufferSize = _samples * 4;
+ ConfMan.flushToDisk();
- _atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
- if (!_atariSampleBuffer)
- error("Failed to allocate memory in ST RAM");
+ _atariSampleBufferSize = _samples * 4;
- _atariPhysicalSampleBuffer = _atariSampleBuffer;
- _atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
+ _atariSampleBuffer = (byte*)Mxalloc(_atariSampleBufferSize * 2, MX_STRAM);
+ if (!_atariSampleBuffer)
+ error("Failed to allocate memory in ST RAM");
- memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
+ _atariPhysicalSampleBuffer = _atariSampleBuffer;
+ _atariLogicalSampleBuffer = _atariSampleBuffer + _atariSampleBufferSize;
- Setmode(MODE_STEREO16);
- Soundcmd(ADDERIN, MATIN);
- Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
- Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+ Setmode(MODE_STEREO16);
+ Soundcmd(ADDERIN, MATIN);
+ Setbuffer(SR_PLAY, _atariSampleBuffer, _atariSampleBuffer + 2 * _atariSampleBufferSize);
- _samplesBuf = new uint8[_samples * 4];
- }
+ _samplesBuf = new uint8[_samples * 4];
_mixer = new Audio::MixerImpl(_outputRate, _samples);
_mixer->setReady(true);
@@ -210,41 +189,28 @@ void AtariMixerManager::init() {
}
void AtariMixerManager::suspendAudio() {
- if (s_audioNotAvailable)
- return;
-
debug("suspendAudio");
- Buffoper(0x00);
+ stopPlayback(kPlaybackStopped);
_audioSuspended = true;
}
int AtariMixerManager::resumeAudio() {
- if (s_audioNotAvailable)
- return 0;
-
debug("resumeAudio");
- Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+ update();
_audioSuspended = false;
return 0;
}
bool AtariMixerManager::notifyEvent(const Common::Event &event) {
- if (s_audioNotAvailable)
- return false;
-
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
- debug("silencing the mixer"); // TODO: is it for long enough?
- memset(_atariSampleBuffer, 0, 2 * _atariSampleBufferSize);
- return false;
- case Common::EVENT_MUTE:
- _muted = !_muted;
- debug("audio %s", _muted ? "off" : "on");
+ stopPlayback(kPlaybackStopped);
+ debug("silencing the mixer");
return false;
default:
[[fallthrough]];
@@ -253,44 +219,67 @@ bool AtariMixerManager::notifyEvent(const Common::Event &event) {
return false;
}
+void AtariMixerManager::startPlayback(PlaybackState playbackState) {
+ Buffoper(SB_PLA_ENA | SB_PLA_RPT);
+ _playbackState = playbackState;
+ debug("playback started");
+}
+
+void AtariMixerManager::stopPlayback(PlaybackState playbackState) {
+ Buffoper(0x00);
+ _playbackState = playbackState;
+ debug("playback stopped");
+}
+
void AtariMixerManager::update() {
if (_audioSuspended) {
return;
}
- if (s_audioNotAvailable) {
- static byte dummy[4];
- _mixer->mixCallback(dummy, 0);
- return;
- }
+ assert(_mixer);
- static bool loadSampleFlag = true;
- byte *buf = nullptr;
-
- SndBufPtr sPtr;
- if (Buffptr(&sPtr) != 0)
- return;
+ uint32 processed = 0;
+ if (_playbackState == kPlaybackStopped) {
+ // playback stopped means that we are not playing anything (DMA
+ // pointer is not updating) but the mixer may have something available
+ processed = _mixer->mixCallback(_samplesBuf, _samples * 4);
- if (!loadSampleFlag) {
- if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
- buf = _atariLogicalSampleBuffer;
- loadSampleFlag = !loadSampleFlag;
+ if (processed > 0) {
+ memcpy(_atariPhysicalSampleBuffer, _samplesBuf, processed * 4);
+ startPlayback(kPlayingFromPhysicalBuffer);
}
} else {
- if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
- buf = _atariPhysicalSampleBuffer;
- loadSampleFlag = !loadSampleFlag;
+ SndBufPtr sPtr;
+ if (Buffptr(&sPtr) != 0) {
+ warning("Buffptr() failed");
+ return;
}
- }
- if (buf != nullptr) {
- assert(_mixer);
- // generates stereo 16-bit samples
- int processed = _mixer->mixCallback(_samplesBuf, _muted ? 0 : _samples * 4);
- if (processed > 0) {
- memcpy(buf, _samplesBuf, processed * 4);
- } else {
- memset(buf, 0, _atariSampleBufferSize);
+ byte *buf = nullptr;
+
+ if (_playbackState == kPlayingFromPhysicalBuffer) {
+ if ((byte*)sPtr.play < _atariLogicalSampleBuffer) {
+ buf = _atariLogicalSampleBuffer;
+ _playbackState = kPlayingFromLogicalBuffer;
+ }
+ } else if (_playbackState == kPlayingFromLogicalBuffer) {
+ if ((byte*)sPtr.play >= _atariLogicalSampleBuffer) {
+ buf = _atariPhysicalSampleBuffer;
+ _playbackState = kPlayingFromPhysicalBuffer;
+ }
}
+
+ if (buf) {
+ processed = _mixer->mixCallback(_samplesBuf, _samples * 4);
+ if (processed > 0) {
+ memcpy(buf, _samplesBuf, processed * 4);
+ } else {
+ stopPlayback(kPlaybackStopped);
+ }
+ }
+ }
+
+ if (processed > 0 && processed != _samples) {
+ warning("processed: %d, _samples: %d", processed, _samples);
}
}
diff --git a/backends/mixer/atari/atari-mixer.h b/backends/mixer/atari/atari-mixer.h
index b0f7d233cbe..d18c41849af 100644
--- a/backends/mixer/atari/atari-mixer.h
+++ b/backends/mixer/atari/atari-mixer.h
@@ -43,6 +43,15 @@ public:
bool notifyEvent(const Common::Event &event) override;
private:
+ enum PlaybackState {
+ kPlaybackStopped,
+ kPlayingFromPhysicalBuffer,
+ kPlayingFromLogicalBuffer
+ };
+
+ void startPlayback(PlaybackState playbackState);
+ void stopPlayback(PlaybackState playbackState);
+
uint32 _outputRate;
uint32 _samples = 0;
uint8 *_samplesBuf = nullptr;
@@ -52,7 +61,7 @@ private:
byte *_atariLogicalSampleBuffer = nullptr;
size_t _atariSampleBufferSize; // one buffer (logical/physical)
- bool _muted = false;
+ PlaybackState _playbackState = kPlaybackStopped;
};
#endif
diff --git a/backends/module.mk b/backends/module.mk
index f022bb314bd..534b876edec 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -360,7 +360,8 @@ MODULE_OBJS += \
graphics/atari/atari_c2p-asm.o \
graphics/atari/atari-graphics.o \
graphics/atari/atari-graphics-asm.o \
- mixer/atari/atari-mixer.o
+ mixer/atari/atari-mixer.o \
+ mixer/null/null-mixer.o
endif
ifeq ($(BACKEND),ds)
diff --git a/backends/platform/atari/osystem_atari.cpp b/backends/platform/atari/osystem_atari.cpp
index 9a27b38a3ee..8d5f1b2110d 100644
--- a/backends/platform/atari/osystem_atari.cpp
+++ b/backends/platform/atari/osystem_atari.cpp
@@ -50,6 +50,7 @@
#include "backends/graphics/atari/atari-graphics.h"
#include "backends/keymapper/hardware-input.h"
#include "backends/mixer/atari/atari-mixer.h"
+#include "backends/mixer/null/null-mixer.h"
#include "backends/mutex/null/null-mutex.h"
#include "backends/saves/default/default-saves.h"
#include "backends/timer/default/default-timer.h"
@@ -253,7 +254,24 @@ void OSystem_Atari::initBackend() {
atariEventSource->setGraphicsManager(atariGraphicsManager);
- _mixerManager = new AtariMixerManager();
+#ifdef DISABLE_FANCY_THEMES
+ // On the slim build force "STMIDI" as GM MIDI device, i.e. do not attempt
+ // to emulate anything by default. That prevents mixing silence and enable
+ // us to stop DMA playback which takes cycles especially on TT with STFA's
+ // emulation.
+ if (!ConfMan.hasKey("gm_device")) {
+ ConfMan.set("gm_device", "stmidi");
+ }
+#endif
+
+ long cookie;
+ if (Getcookie(C__SND, &cookie) == C_FOUND && (cookie & SND_16BIT)) {
+ _mixerManager = new AtariMixerManager();
+ } else {
+ warning("Mixer manager requires 16-bit stereo mode, disabling");
+ _mixerManager = new NullMixerManager();
+ _useNullMixer = true;
+ }
// Setup and start mixer
_mixerManager->init();
@@ -374,7 +392,10 @@ Common::String OSystem_Atari::getDefaultConfigFileName() {
void OSystem_Atari::update() {
((DefaultTimerManager *)_timerManager)->checkTimers();
- ((AtariMixerManager *)_mixerManager)->update();
+ if (_useNullMixer)
+ ((NullMixerManager *)_mixerManager)->update();
+ else
+ ((AtariMixerManager *)_mixerManager)->update();
}
OSystem *OSystem_Atari_create() {
diff --git a/backends/platform/atari/osystem_atari.h b/backends/platform/atari/osystem_atari.h
index d5ea05cc04f..898115b7379 100644
--- a/backends/platform/atari/osystem_atari.h
+++ b/backends/platform/atari/osystem_atari.h
@@ -53,6 +53,7 @@ private:
bool _videoInitialized = false;
bool _timerInitialized = false;
+ bool _useNullMixer = false;
};
#endif
diff --git a/backends/platform/atari/readme.txt b/backends/platform/atari/readme.txt
index 4691f1e9355..a2c30d8a7c2 100644
--- a/backends/platform/atari/readme.txt
+++ b/backends/platform/atari/readme.txt
@@ -81,9 +81,6 @@ Main features
Platform-specific features outside the GUI
------------------------------------------
-Keyboard shortcut "CONTROL+u": immediate mute on/off toggle (disables also
-sample mixing, contrary to what "Mute all" in the options does!)
-
Keyboard shortcut "CONTROL+ALT+a": immediate aspect ratio correction on/off
toggle.
@@ -265,10 +262,10 @@ or "FM_medium_quality=true" into scummvm.ini if you want to experiment with a
better quality synthesis, otherwise the lowest quality will be used (applies
for MAME OPL only).
-On the TT, in 95% of cases it makes sense to enable music only if you have a
-native MIDI synthesizer (like mt32-pi: https://github.com/dwhinham/mt32-pi);
-STFA is usually slow to mix samples, too => mute it (see below) or don't
-install STFA (same effect).
+On the TT, in 95% of cases it makes sense to use ScummVM only if you own a
+native MIDI synthesizer (like mt32-pi: https://github.com/dwhinham/mt32-pi).
+MIDI emulation is out of question and STFA is usually slow to mix samples, too
+=> stick with games with MIDI sounds or at least don't install/enable STFA.
CD music slows everything down
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -283,26 +280,22 @@ rendering. Try to put "musdisk1.bun" and "musdisk2.bun" into a ramdisk (i.e.
u:/ram in FreeMiNT), you'll be pleasantly surprised with the performance boost
gained.
-"Mute" vs. "Mute all" in GUI vs. "No music" in GUI
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Not the same thing. "Mute" (available only via the shortcut CONTROL+u) generates
-an event to which the sample mixer can react (i.e. stop mixing the silence...).
+Mute vs. "No music"
+~~~~~~~~~~~~~~~~~~~
-"Mute all" doesn't generate anything, it basically just lowers the volume of the
-music to zero.
+Currently ScummVM requires each backend to mix samples, even though they may
+contain muted output (i.e. zeroes). This is because the progression of sample
+playback tells ScummVM how much time has passed in e.g. an animation.
"No music" means using the null audio plugin which prevents generating any MIDI
music (and therefore avoiding the expensive synthesis emulation) but beware, it
-doesn't affect CD (*.wav) playback at all!
+doesn't affect CD (*.wav) playback at all! Same applies for speech and sfx.
-So for the best performance, always choose "No music" in the GUI options when
-the game contains MIDI tracks and "Mute" when the game contains a sampled
-soundtrack.
-
-Please note that it is not that bad, you surely can play The Secret of Monkey
-Island with AdLib enabled (but the CD/talkie versions sound better and
-are cheaper to play ;)).
+The least amount of cycles is spent when:
+- "No music" (or keep it default and choose a native MIDI device) is set in the
+ GUI options; this prevents MIDI sythesis of any kind
+- all external audio files are deleted (typically *.wav); that way the mixer
+ wont have anything to mix. However beware, this is not allowed in every game!
Slow GUI
~~~~~~~~
@@ -333,6 +326,9 @@ restricts features but also improves performance:
- overlay doesn't support alternative themes => faster loading time
+- "STMIDI" driver is automatically enabled (i.e. MIDI emulation is never used
+ but still allows playing speech/sfx samples and/or CD audio)
+
Known issues
------------
Commit: d9eee7906ab544ad15fc8d4c5f68c80a0c7e7f71
https://github.com/scummvm/scummvm/commit/d9eee7906ab544ad15fc8d4c5f68c80a0c7e7f71
Author: Miro Kropacek (miro.kropacek at gmail.com)
Date: 2023-06-15T22:58:13+02:00
Commit Message:
BACKENDS: ATARI: Use unordered_set for dirty rects
This allows efficient redraw of surfaces which don't change their
position too much.
Changed paths:
backends/events/atari/atari-events.cpp
backends/graphics/atari/atari-graphics.cpp
backends/graphics/atari/atari-graphics.h
diff --git a/backends/events/atari/atari-events.cpp b/backends/events/atari/atari-events.cpp
index 01c6841362c..25a5158e7b2 100644
--- a/backends/events/atari/atari-events.cpp
+++ b/backends/events/atari/atari-events.cpp
@@ -19,6 +19,8 @@
*
*/
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE // atari-graphics.h's unordered_set
+
#include "backends/events/atari/atari-events.h"
#include <mint/osbind.h>
diff --git a/backends/graphics/atari/atari-graphics.cpp b/backends/graphics/atari/atari-graphics.cpp
index 043035a7e85..9778277f714 100644
--- a/backends/graphics/atari/atari-graphics.cpp
+++ b/backends/graphics/atari/atari-graphics.cpp
@@ -19,6 +19,8 @@
*
*/
+#define FORBIDDEN_SYMBOL_EXCEPTION_FILE // atari-graphics.h's unordered_set
+
#include "backends/graphics/atari/atari-graphics.h"
#include <mint/cookie.h>
@@ -444,20 +446,20 @@ void AtariGraphicsManager::updateScreen() {
if (isOverlayVisible()) {
assert(_workScreen == _screen[OVERLAY_BUFFER]);
- screenUpdated = updateScreenInternal(_overlaySurface, _workScreen->dirtyRects);
+ screenUpdated = updateScreenInternal(_overlaySurface);
} else {
switch (_currentState.mode) {
case GraphicsMode::DirectRendering:
assert(_workScreen == _screen[FRONT_BUFFER]);
- screenUpdated = updateScreenInternal(Graphics::Surface(), _workScreen->dirtyRects);
+ screenUpdated = updateScreenInternal(Graphics::Surface());
break;
case GraphicsMode::SingleBuffering:
assert(_workScreen == _screen[FRONT_BUFFER]);
- screenUpdated = updateScreenInternal(_chunkySurface, _workScreen->dirtyRects);
+ screenUpdated = updateScreenInternal(_chunkySurface);
break;
case GraphicsMode::TripleBuffering:
assert(_workScreen == _screen[BACK_BUFFER1]);
- screenUpdated = updateScreenInternal(_chunkySurface, _workScreen->dirtyRects);
+ screenUpdated = updateScreenInternal(_chunkySurface);
break;
}
}
@@ -866,9 +868,10 @@ void AtariGraphicsManager::convertRectToSurfaceWithKey(Graphics::Surface &dstSur
}
}
-bool AtariGraphicsManager::updateScreenInternal(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects) {
+bool AtariGraphicsManager::updateScreenInternal(const Graphics::Surface &srcSurface) {
//debug("updateScreenInternal: %d", (int)dirtyRects.size());
+ const DirtyRects &dirtyRects = _workScreen->dirtyRects;
Graphics::Surface *dstSurface = _workScreen->offsettedSurf;
bool &cursorPositionChanged = _workScreen->cursorPositionChanged;
bool &cursorSurfaceChanged = _workScreen->cursorSurfaceChanged;
@@ -1081,17 +1084,17 @@ void AtariGraphicsManager::Screen::addDirtyRect(const Graphics::Surface &srcSurf
rect.right = (rect.right + 15) & 0xfff0;
if ((rect.width() == srcSurface.w && rect.height() == srcSurface.h)
- || dirtyRects.size() == dirtyRects.capacity()) {
+ || dirtyRects.size() == 128) { // 320x200 can hold at most 250 16x16 rectangles
//debug("addDirtyRect[%d]: purge %d x %d", (int)dirtyRects.size(), srcSurface.w, srcSurface.h);
dirtyRects.clear();
- dirtyRects.push_back(Common::Rect(srcSurface.w, srcSurface.h));
+ dirtyRects.emplace(srcSurface.w, srcSurface.h);
fullRedraw = true;
return;
}
- dirtyRects.push_back(rect);
+ dirtyRects.emplace(std::move(rect));
}
void AtariGraphicsManager::Cursor::update(const Graphics::Surface &screen, bool isModified) {
diff --git a/backends/graphics/atari/atari-graphics.h b/backends/graphics/atari/atari-graphics.h
index 49c991b63d4..17e465f08cf 100644
--- a/backends/graphics/atari/atari-graphics.h
+++ b/backends/graphics/atari/atari-graphics.h
@@ -23,15 +23,26 @@
#define BACKENDS_GRAPHICS_ATARI_H
#include "backends/graphics/graphics.h"
+#include "common/events.h"
#include <mint/osbind.h>
#include <mint/ostruct.h>
-#include <vector>
+#include <unordered_set>
-#include "common/events.h"
#include "common/rect.h"
#include "graphics/surface.h"
+template<>
+struct std::hash<Common::Rect>
+{
+ std::size_t operator()(Common::Rect const& rect) const noexcept
+ {
+ return 31 * (31 * (31 * rect.left + rect.top) + rect.right) + rect.bottom;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
class AtariGraphicsManager : public GraphicsManager, Common::EventObserver {
public:
AtariGraphicsManager();
@@ -128,8 +139,7 @@ protected:
GraphicsState _pendingState{ (GraphicsMode)getDefaultGraphicsMode() };
private:
- // use std::vector as its clear() doesn't reset capacity
- using DirtyRects = std::vector<Common::Rect>;
+ using DirtyRects = std::unordered_set<Common::Rect>;
enum CustomEventAction {
kActionToggleAspectRatioCorrection = 100,
@@ -147,7 +157,7 @@ private:
int16 getMaximumScreenHeight() const { return 480; }
int16 getMaximumScreenWidth() const { return _tt ? 320 : (_vgaMonitor ? 640 : 640*1.2); }
- bool updateScreenInternal(const Graphics::Surface &srcSurface, const DirtyRects &dirtyRects);
+ bool updateScreenInternal(const Graphics::Surface &srcSurface);
virtual AtariMemAlloc getStRamAllocFunc() const {
return [](size_t bytes) { return (void*)Mxalloc(bytes, MX_STRAM); };
@@ -261,7 +271,7 @@ private:
bool cursorPositionChanged = true;
bool cursorSurfaceChanged = false;
bool cursorVisibilityChanged = false;
- DirtyRects dirtyRects = DirtyRects(512); // reserve 512 rects
+ DirtyRects dirtyRects;
bool fullRedraw = false;
Common::Rect oldCursorRect;
int rez = -1;
More information about the Scummvm-git-logs
mailing list