BACKENDS: ATARI: Refactor

This commit is contained in:
Miro Kropacek 2023-03-05 14:30:47 +01:00
parent 740cf0989c
commit 6c5e3dbfd5
14 changed files with 303 additions and 293 deletions

View File

@ -19,8 +19,6 @@
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_time_h
#include "backends/events/atari/atari-events.h"
#include <mint/osbind.h>
@ -122,7 +120,7 @@ bool AtariEventSource::pollEvent(Common::Event &event) {
if (curMillis - startMillis >= 1000) {
float avgFps = avgFpsSum / avgFpsCount;
debug("*** Average FPS in 1s: %f ***", avgFps);
//debug("*** Average FPS in 1s: %f ***", avgFps);
startMillis = curMillis;
avgFpsSum = 0;
avgFpsCount = 0;

View File

@ -22,32 +22,20 @@
#ifndef BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
#define BACKENDS_GRAPHICS_ATARI_SUPERBLITTER_H
#include <mint/trap14.h>
#include <mint/cookie.h>
#include <mint/falcon.h>
#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
#define ct60_vmalloc(value) ct60_vm(0, value)
#define ct60_vmfree(value) ct60_vm(1, value)
// bits 26:0
#define SV_BLITTER_SRC1 ((volatile long*)0x80010058)
#define SV_BLITTER_SRC2 ((volatile long*)0x8001005C)
#define SV_BLITTER_DST ((volatile long*)0x80010060)
// The amount of bytes that are to be copied in a horizontal line, minus 1
#define SV_BLITTER_COUNT ((volatile long*)0x80010064)
// The amount of bytes that are to be added to the line start adress after a line has been copied, in order to reach the next one
#define SV_BLITTER_SRC1_OFFSET ((volatile long*)0x80010068)
#define SV_BLITTER_SRC2_OFFSET ((volatile long*)0x8001006C)
#define SV_BLITTER_DST_OFFSET ((volatile long*)0x80010070)
// bits 11:0 - The amount of horizontal lines to do
#define SV_BLITTER_MASK_AND_LINES ((volatile long*)0x80010074)
// bit 0 - busy / start
// bits 4:1 - blit mode
#define SV_BLITTER_CONTROL ((volatile long*)0x80010078)
// bits 9:0
#define SV_VERSION ((volatile long*)0x8001007C)
// bit 0 - empty (read only)
// bit 1 - full (read only)
// bits 31:0 - data (write only)
#define SV_BLITTER_FIFO ((volatile long*)0x80010080)
#define SV_VERSION ((volatile long*)0x8001007C)
inline static bool hasSuperVidel() {
static bool hasSuperVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
return hasSuperVidel;
}
static int superVidelFwVersion = hasSuperVidel() ? *SV_VERSION & 0x01ff : 0;
void lockSuperBlitter();
void unlockSuperBlitter();
#endif

View File

@ -22,75 +22,42 @@
#ifndef BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
#define BACKENDS_GRAPHICS_ATARI_SUPERVIDEL_H
#define USE_SV_BLITTER // TODO: into configure?
#include "backends/graphics/atari/atari-graphics.h"
#include <cstring>
#include <mint/osbind.h>
#ifdef USE_SV_BLITTER
#include "backends/graphics/atari/atari-graphics-superblitter.h"
#endif
#include "backends/graphics/atari/videl-resolutions.h"
#include "common/debug.h" // error() & warning()
#include "common/scummsys.h"
#include "common/textconsole.h" // for error()
class AtariSuperVidelManager : public AtariGraphicsManager {
public:
AtariSuperVidelManager() {
#ifdef USE_SV_BLITTER
_fwVersion = *SV_VERSION & 0x01ff;
debug("SuperVidel FW Revision: %d, using %s", _fwVersion, _fwVersion >= 9
? "fast async FIFO" : "slower sync blitting" );
debug("SuperVidel FW Revision: %d, using %s", superVidelFwVersion, superVidelFwVersion >= 9
? "fast async FIFO" : "slower sync blitting");
#else
debug("SuperVidel FW Revision: %d, SuperBlitter not used", superVidelFwVersion);
#endif
for (int i = 0; i < SCREENS; ++i) {
if (!allocateAtariSurface(_screen[i], _screenSurface,
SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8,
MX_STRAM, 0xA0000000))
error("Failed to allocate screen memory in ST RAM");
_screenAligned[i] = (byte*)_screenSurface.getPixels();
}
_screenSurface.setPixels(_screenAligned[getDefaultGraphicsMode() <= 1 ? FRONT_BUFFER : BACK_BUFFER1]);
if (!allocateAtariSurface(_chunkyBuffer, _chunkySurface,
SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8,
MX_PREFTTRAM))
error("Failed to allocate chunky buffer memory in ST/TT RAM");
if (!allocateAtariSurface(_overlayScreen, _screenOverlaySurface,
getOverlayWidth(), getOverlayHeight(), getOverlayFormat(),
MX_STRAM, 0xA0000000))
error("Failed to allocate overlay memory in ST RAM");
if (!allocateAtariSurface(_overlayBuffer, _overlaySurface,
getOverlayWidth(), getOverlayHeight(), getOverlayFormat(),
MX_PREFTTRAM))
error("Failed to allocate overlay buffer memory in ST/TT RAM");
if (Supexec(hasSvRamBoosted))
debug("SV_XBIOS has the pmmu boost enabled");
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();
}
~AtariSuperVidelManager() {
#ifdef USE_SV_BLITTER
ct60_vmfree(_chunkyBuffer);
#else
Mfree(_chunkyBuffer);
#endif
_chunkyBuffer = nullptr;
#ifdef USE_SV_BLITTER
ct60_vmfree(_overlayBuffer);
#else
Mfree(_overlayBuffer);
#endif
_overlayBuffer = nullptr;
// using virtual methods so must be done here
freeSurfaces();
}
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override {
@ -107,95 +74,56 @@ public:
int16 getOverlayHeight() const override { return 2 * OVERLAY_HEIGHT; }
int16 getOverlayWidth() const override { return 2 * OVERLAY_WIDTH; }
protected:
AtariMemAlloc getStRamAllocFunc() const override {
return [](size_t bytes) {
uintptr ptr = Mxalloc(bytes, MX_STRAM);
if (ptr != 0)
ptr |= 0xA0000000;
return (void*)ptr;
};
}
AtariMemFree getStRamFreeFunc() const override {
return [](void *ptr) { Mfree((uintptr)ptr & 0x00FFFFFF); };
}
private:
virtual void* allocFast(size_t bytes) const override {
#ifdef USE_SV_BLITTER
return (void*)ct60_vmalloc(bytes);
#else
return (void*)Mxalloc(bytes, MX_PREFTTRAM);
#endif
}
void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const override {
#ifdef USE_SV_BLITTER
if (_fwVersion >= 9) {
*SV_BLITTER_FIFO = (long)srcSurface.getPixels(); // SV_BLITTER_SRC1
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2
*SV_BLITTER_FIFO = (long)dstSurface.getPixels(); // SV_BLITTER_DST
*SV_BLITTER_FIFO = srcSurface.w - 1; // SV_BLITTER_COUNT
*SV_BLITTER_FIFO = srcSurface.pitch; // SV_BLITTER_SRC1_OFFSET
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2_OFFSET
*SV_BLITTER_FIFO = dstSurface.pitch; // SV_BLITTER_DST_OFFSET
*SV_BLITTER_FIFO = srcSurface.h; // SV_BLITTER_MASK_AND_LINES
*SV_BLITTER_FIFO = 0x01; // SV_BLITTER_CONTROL
} else {
sync();
*SV_BLITTER_SRC1 = (long)srcSurface.getPixels();
*SV_BLITTER_SRC2 = 0x00000000;
*SV_BLITTER_DST = (long)dstSurface.getPixels();
*SV_BLITTER_COUNT = srcSurface.w - 1;
*SV_BLITTER_SRC1_OFFSET = srcSurface.pitch;
*SV_BLITTER_SRC2_OFFSET = 0x00000000;
*SV_BLITTER_DST_OFFSET = dstSurface.pitch;
*SV_BLITTER_MASK_AND_LINES = srcSurface.h;
*SV_BLITTER_CONTROL = 0x01;
}
#else
memcpy(dstSurface.getPixels(), srcSurface.getPixels(), srcSurface.h * srcSurface.pitch);
#endif
}
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, Graphics::Surface &dstSurface,
void copyRectToSurface(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect) const override {
#ifdef USE_SV_BLITTER
if (_fwVersion >= 9) {
*SV_BLITTER_FIFO = (long)srcSurface.getBasePtr(subRect.left, subRect.top); // SV_BLITTER_SRC1
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2
*SV_BLITTER_FIFO = (long)dstSurface.getBasePtr(destX, destY); // SV_BLITTER_DST
*SV_BLITTER_FIFO = subRect.width() - 1; // SV_BLITTER_COUNT
*SV_BLITTER_FIFO = srcSurface.pitch; // SV_BLITTER_SRC1_OFFSET
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2_OFFSET
*SV_BLITTER_FIFO = dstSurface.pitch; // SV_BLITTER_DST_OFFSET
*SV_BLITTER_FIFO = subRect.height(); // SV_BLITTER_MASK_AND_LINES
*SV_BLITTER_FIFO = 0x01; // SV_BLITTER_CONTROL
} else {
sync();
*SV_BLITTER_SRC1 = (long)srcSurface.getBasePtr(subRect.left, subRect.top);
*SV_BLITTER_SRC2 = 0x00000000;
*SV_BLITTER_DST = (long)dstSurface.getBasePtr(destX, destY);
*SV_BLITTER_COUNT = subRect.width() - 1;
*SV_BLITTER_SRC1_OFFSET = srcSurface.pitch;
*SV_BLITTER_SRC2_OFFSET = 0x00000000;
*SV_BLITTER_DST_OFFSET = dstSurface.pitch;
*SV_BLITTER_MASK_AND_LINES = subRect.height();
*SV_BLITTER_CONTROL = 0x01;
}
#else
dstSurface.copyRectToSurface(srcSurface, destX, destY, subRect);
#endif
}
void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY, Graphics::Surface &dstSurface,
void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect, uint32 key) const override {
sync();
dstSurface.copyRectToSurfaceWithKey(srcSurface, destX, destY, subRect, key);
}
virtual void sync() const override {
#ifdef USE_SV_BLITTER
// while FIFO not empty...
if (_fwVersion >= 9)
while (!(*SV_BLITTER_FIFO & 1));
// while busy blitting...
while (*SV_BLITTER_CONTROL & 1);
#endif
}
static long hasSvRamBoosted() {
register long ret __asm__ ("d0") = 0;
#ifdef USE_SV_BLITTER
int _fwVersion = 0;
#endif
__asm__ volatile(
"\tmovec %%itt0,%%d1\n"
"\tcmp.l #0xA007E060,%%d1\n"
"\tbne.s 1f\n"
"\tmovec %%dtt0,%%d1\n"
"\tcmp.l #0xA007E060,%%d1\n"
"\tbne.s 1f\n"
"\tmoveq #1,%%d0\n"
"1:\n"
: "=g"(ret) /* outputs */
: /* inputs */
: __CLOBBER_RETURN("d0") "d1", "cc"
);
return ret;
}
};
#endif

View File

@ -24,40 +24,19 @@
#include "backends/graphics/atari/atari-graphics.h"
#include <mint/osbind.h>
#include "backends/graphics/atari/atari_c2p-asm.h"
#include "common/system.h"
#include "common/textconsole.h" // for error()
class AtariVidelManager : public AtariGraphicsManager {
public:
AtariVidelManager() {
for (int i = 0; i < SCREENS; ++i) {
if (!allocateAtariSurface(_screen[i], _screenSurface, SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8, MX_STRAM))
error("Failed to allocate screen memory in ST RAM");
_screenAligned[i] = (byte*)_screenSurface.getPixels();
}
_screenSurface.setPixels(_screenAligned[getDefaultGraphicsMode() <= 1 ? FRONT_BUFFER : BACK_BUFFER1]);
if (!allocateAtariSurface(_chunkyBuffer, _chunkySurface, SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8, MX_PREFTTRAM))
error("Failed to allocate chunky buffer memory in ST/TT RAM");
if (!allocateAtariSurface(_overlayScreen, _screenOverlaySurface, getOverlayWidth(), getOverlayHeight(),
getOverlayFormat(), MX_STRAM))
error("Failed to allocate overlay memory in ST RAM");
if (!allocateAtariSurface(_overlayBuffer, _overlaySurface, getOverlayWidth(), getOverlayHeight(),
getOverlayFormat(), MX_PREFTTRAM))
error("Failed to allocate overlay buffer memory in ST/TT RAM");
// using virtual methods so must be done here
allocateSurfaces();
}
~AtariVidelManager() {
Mfree(_chunkyBuffer);
_chunkyBuffer = nullptr;
Mfree(_overlayBuffer);
_overlayBuffer = nullptr;
// using virtual methods so must be done here
freeSurfaces();
}
virtual const OSystem::GraphicsMode *getSupportedGraphicsModes() const override {
@ -89,35 +68,35 @@ public:
int16 getOverlayWidth() const override { return _vgaMonitor ? OVERLAY_WIDTH : 2 * OVERLAY_WIDTH; }
private:
virtual void* allocFast(size_t bytes) const override {
return (void*)Mxalloc(bytes, MX_PREFTTRAM);
}
void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const override {
asm_c2p1x1_8(
(const byte*)srcSurface.getPixels(),
(const byte*)srcSurface.getBasePtr(srcSurface.w, srcSurface.h-1),
(byte*)dstSurface.getPixels());
}
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY,
Graphics::Surface &dstSurface, const Common::Rect &subRect) const override {
void copyRectToSurface(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect) const override {
// 'pChunkyEnd' is a delicate parameter: the c2p routine compares it to the address register
// used for pixel reading; two common mistakes:
// 1. (subRect.left, subRect.bottom) = beginning of the next line *including the offset*
// 2. (subRect.right, subRect.bottom) = even worse, end of the *next* line, not current one
asm_c2p1x1_8_rect(
(const byte*)srcSurface.getBasePtr(subRect.left, subRect.top),
(const byte*)srcSurface.getBasePtr(subRect.right, subRect.bottom-1),
subRect.width(),
srcSurface.pitch,
(byte*)dstSurface.getBasePtr(destX, destY),
dstSurface.pitch);
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 {
asm_c2p1x1_8_rect(
(const byte*)srcSurface.getBasePtr(subRect.left, subRect.top),
(const byte*)srcSurface.getBasePtr(subRect.right, subRect.bottom-1),
subRect.width(),
srcSurface.pitch,
(byte*)dstSurface.getBasePtr(destX, destY),
dstSurface.pitch);
}
}
// TODO: allow specifying different background than _chunkySurface?
void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY,
Graphics::Surface &dstSurface, const Common::Rect &subRect, uint32 key) const override {
// TODO: alignRect and this function could be perhaps better if we know that all surfaces
// are aligned on 16px and their pitch is % 16 as well?
void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect, uint32 key) 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
@ -144,9 +123,9 @@ private:
cachedSurface.copyRectToSurfaceWithKey(srcSurface, deltaX, 0, subRect, key);
copyRectToSurface(
dstSurface,
cachedSurface,
backgroundRect.left, backgroundRect.top,
dstSurface,
Common::Rect(cachedSurface.w, cachedSurface.h));
}

View File

@ -26,6 +26,7 @@
#include <mint/osbind.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"
@ -67,14 +68,6 @@ AtariGraphicsManager::AtariGraphicsManager() {
AtariGraphicsManager::~AtariGraphicsManager() {
g_system->getEventManager()->getEventDispatcher()->unregisterObserver(this);
for (int i = 0; i < SCREENS; ++i) {
Mfree(_screen[i]);
_screen[i] = _screenAligned[i] = nullptr;
}
Mfree(_overlayScreen);
_overlayScreen = nullptr;
}
bool AtariGraphicsManager::hasFeature(OSystem::Feature f) const {
@ -293,6 +286,8 @@ void AtariGraphicsManager::updateScreen() {
bool screenUpdated = false;
lockSuperBlitter();
if (isOverlayVisible()) {
screenUpdated = updateOverlay();
} else {
@ -310,14 +305,14 @@ void AtariGraphicsManager::updateScreen() {
}
}
unlockSuperBlitter();
//if (_cursor.outOfScreen)
// warning("mouse out of screen");
bool vsync = _vsync;
if (_screenModified) {
sync();
if (_currentState.mode == GraphicsMode::DoubleBuffering) {
byte *tmp = _screenAligned[FRONT_BUFFER];
_screenAligned[FRONT_BUFFER] = _screenAligned[BACK_BUFFER1];
@ -532,6 +527,9 @@ void AtariGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int h
bool dontScale, const Graphics::PixelFormat *format, const byte *mask) {
//debug("setMouseCursor: %d, %d, %d, %d, %d, %d", w, h, hotspotX, hotspotY, keycolor, format ? format->bytesPerPixel : 1);
if (mask)
warning("AtariGraphicsManager::setMouseCursor: Masks are not supported");
const Graphics::PixelFormat cursorFormat = format ? *format : PIXELFORMAT8;
_cursor.setSurface(buf, (int)w, (int)h, hotspotX, hotspotY, keycolor, cursorFormat);
}
@ -575,21 +573,38 @@ Common::Keymap *AtariGraphicsManager::getKeymap() const {
return keymap;
}
bool AtariGraphicsManager::allocateAtariSurface(
byte *&buf, Graphics::Surface &surface, int width, int height,
const Graphics::PixelFormat &format, int mode, uintptr mask) {
buf = (mode == MX_STRAM)
? (byte*)Mxalloc(width * height * format.bytesPerPixel + 15, mode)
: (byte*)allocFast(width * height * format.bytesPerPixel + 15);
void AtariGraphicsManager::allocateSurfaces() {
for (int i = 0; i < SCREENS; ++i) {
if (!(_screen[i] = allocateAtariSurface(_screenSurface,
SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8,
getStRamAllocFunc())))
error("Failed to allocate screen memory in ST RAM");
_screenAligned[i] = (byte*)_screenSurface.getPixels();
}
_screenSurface.setPixels(_screenAligned[getDefaultGraphicsMode() <= 1 ? FRONT_BUFFER : BACK_BUFFER1]);
if (!buf)
return false;
_chunkySurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, PIXELFORMAT8);
byte *bufAligned = (byte*)((((uintptr)buf + 15) | mask) & 0xfffffff0);
memset(bufAligned, 0, width * height * format.bytesPerPixel);
if (!(_overlayScreen = allocateAtariSurface(_screenOverlaySurface,
getOverlayWidth(), getOverlayHeight(), getOverlayFormat(),
getStRamAllocFunc())))
error("Failed to allocate overlay memory in ST RAM");
surface.init(width, height, width * format.bytesPerPixel, bufAligned, format);
return true;
_overlaySurface.create(getOverlayWidth(), getOverlayHeight(), getOverlayFormat());
}
void AtariGraphicsManager::freeSurfaces() {
for (int i = 0; i < SCREENS; ++i) {
freeAtariSurface(_screen[i], _screenSurface, getStRamFreeFunc());
_screen[i] = _screenAligned[i] = nullptr;
}
_chunkySurface.free();
freeAtariSurface(_overlayScreen, _screenOverlaySurface, getStRamFreeFunc());
_overlayScreen = nullptr;
_overlaySurface.free();
}
void AtariGraphicsManager::setVidelResolution() const {
@ -755,10 +770,7 @@ bool AtariGraphicsManager::updateSingleBuffer() {
if (!drawCursor && !_cursor.outOfScreen && _cursor.visible)
drawCursor = rect.intersects(_cursor.dstRect);
if (rect.width() == _screenSurface.w && rect.height() == _screenSurface.h)
copySurfaceToSurface(_chunkySurface, _screenSurface);
else
copyRectToSurface(_chunkySurface, rect.left, rect.top, _screenSurface, rect);
copyRectToSurface(_screenSurface, _chunkySurface, rect.left, rect.top, rect);
_modifiedChunkyRects.pop_back();
@ -770,8 +782,10 @@ bool AtariGraphicsManager::updateSingleBuffer() {
if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty()) {
alignRect(_chunkySurface, _oldCursorRect);
copyRectToSurface(_chunkySurface, _oldCursorRect.left, _oldCursorRect.top,
_screenSurface, _oldCursorRect);
copyRectToSurface(
_screenSurface, _chunkySurface,
_oldCursorRect.left, _oldCursorRect.top,
_oldCursorRect);
_oldCursorRect = Common::Rect();
@ -780,8 +794,10 @@ bool AtariGraphicsManager::updateSingleBuffer() {
if (drawCursor && _cursor.visible) {
//debug("Redraw cursor (single): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
copyRectToSurfaceWithKey(_cursor.surface, _cursor.dstRect.left, _cursor.dstRect.top,
_screenSurface, _cursor.srcRect, _cursor.keycolor);
copyRectToSurfaceWithKey(
_screenSurface, _cursor.surface,
_cursor.dstRect.left, _cursor.dstRect.top,
_cursor.srcRect, _cursor.keycolor);
_cursor.positionChanged = _cursor.surfaceChanged = false;
_oldCursorRect = _cursor.dstRect;
@ -799,7 +815,10 @@ bool AtariGraphicsManager::updateDoubleAndTripleBuffer() {
if (_screenModified) {
drawCursor = true;
copySurfaceToSurface(_chunkySurface, _screenSurface);
copyRectToSurface(
_screenSurface, _chunkySurface,
0, 0,
Common::Rect(_chunkySurface.w, _chunkySurface.h));
// updated in screen swapping
//_screenModified = false;
@ -816,8 +835,10 @@ bool AtariGraphicsManager::updateDoubleAndTripleBuffer() {
if ((_cursor.positionChanged || !_cursor.visible) && !_oldCursorRect.isEmpty() && !_screenModified) {
alignRect(_chunkySurface, _oldCursorRect);
copyRectToSurface(_chunkySurface, _oldCursorRect.left, _oldCursorRect.top,
frontBufferScreenSurface, _oldCursorRect);
copyRectToSurface(
frontBufferScreenSurface, _chunkySurface,
_oldCursorRect.left, _oldCursorRect.top,
_oldCursorRect);
_oldCursorRect = Common::Rect();
@ -827,8 +848,10 @@ bool AtariGraphicsManager::updateDoubleAndTripleBuffer() {
if (drawCursor && _cursor.visible) {
//debug("Redraw cursor (double/triple): %d %d %d %d", _cursor.dstRect.left, _cursor.dstRect.top, _cursor.dstRect.width(), _cursor.dstRect.height());
copyRectToSurfaceWithKey(_cursor.surface, _cursor.dstRect.left, _cursor.dstRect.top,
frontBufferScreenSurface, _cursor.srcRect, _cursor.keycolor);
copyRectToSurfaceWithKey(
frontBufferScreenSurface, _cursor.surface,
_cursor.dstRect.left, _cursor.dstRect.top,
_cursor.srcRect, _cursor.keycolor);
_cursor.positionChanged = _cursor.surfaceChanged = false;
_oldCursorRect = _cursor.dstRect;
@ -839,6 +862,26 @@ bool AtariGraphicsManager::updateDoubleAndTripleBuffer() {
return updated;
}
byte *AtariGraphicsManager::allocateAtariSurface(Graphics::Surface &surface,
int width, int height, const Graphics::PixelFormat &format,
const AtariMemAlloc &allocFunc) {
byte *buf = (byte*)allocFunc(width * height * format.bytesPerPixel + 15);
if (!buf)
return buf;
byte *bufAligned = (byte*)(((uintptr)buf + 15) & 0xfffffff0);
memset(bufAligned, 0, width * height * format.bytesPerPixel);
surface.init(width, height, width * format.bytesPerPixel, bufAligned, format);
return buf;
}
void AtariGraphicsManager::freeAtariSurface(byte *ptr, Graphics::Surface &surface,
const AtariMemFree &freeFunc) {
surface = Graphics::Surface();
freeFunc(ptr);
}
void AtariGraphicsManager::copySurface8ToSurface16(
const Graphics::Surface &srcSurface, const byte *srcPalette,
Graphics::Surface &dstSurface, int destX, int destY,

View File

@ -24,6 +24,8 @@
#include "backends/graphics/graphics.h"
#include <mint/osbind.h>
#include "common/array.h"
#include "common/events.h"
#include "common/rect.h"
@ -92,11 +94,20 @@ public:
protected:
const Graphics::PixelFormat PIXELFORMAT8 = Graphics::PixelFormat::createFormatCLUT8();
const Graphics::PixelFormat PIXELFORMAT16 = getOverlayFormat();
bool allocateAtariSurface(byte *&buf, Graphics::Surface &surface,
int width, int height, const Graphics::PixelFormat &format,
int mode, uintptr mask = 0x00000000);
typedef void* (*AtariMemAlloc)(size_t bytes);
typedef void (*AtariMemFree)(void *ptr);
virtual AtariMemAlloc getStRamAllocFunc() const {
return [](size_t bytes) { return (void*)Mxalloc(bytes, MX_STRAM); };
}
virtual AtariMemFree getStRamFreeFunc() const {
return [](void *ptr) { Mfree(ptr); };
}
void allocateSurfaces();
void freeSurfaces();
bool _vgaMonitor = true;
@ -129,18 +140,8 @@ protected:
static const int FRONT_BUFFER = 0;
static const int BACK_BUFFER1 = 1;
static const int BACK_BUFFER2 = 2;
byte *_screen[SCREENS] = {}; // for Mfree() purposes only
byte *_screenAligned[SCREENS] = {};
Graphics::Surface _screenSurface;
byte *_chunkyBuffer = nullptr; // for Mfree() purposes only
Graphics::Surface _chunkySurface;
byte *_overlayScreen = nullptr; // for Mfree() purposes only
Graphics::Surface _screenOverlaySurface;
byte *_overlayBuffer = nullptr; // for Mfree() purposes only
Graphics::Surface _overlaySurface;
Graphics::Surface _chunkySurface; // for Videl's copyRectToSurfaceWithKey
private:
enum CustomEventAction {
@ -155,15 +156,19 @@ private:
bool updateSingleBuffer();
bool updateDoubleAndTripleBuffer();
virtual void* allocFast(size_t bytes) const = 0;
byte *allocateAtariSurface(Graphics::Surface &surface,
int width, int height, const Graphics::PixelFormat &format,
const AtariMemAlloc &allocFunc);
virtual void copySurfaceToSurface(const Graphics::Surface &srcSurface, Graphics::Surface &dstSurface) const = 0;
virtual void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY,
Graphics::Surface &dstSurface, const Common::Rect &subRect) const = 0;
virtual void copyRectToSurfaceWithKey(const Graphics::Surface &srcSurface, int destX, int destY,
Graphics::Surface &dstSurface, const Common::Rect &subRect, uint32 key) const = 0;
void freeAtariSurface(byte *ptr, Graphics::Surface &surface, const AtariMemFree &freeFunc);
virtual void copyRectToSurface(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect) const = 0;
virtual void copyRectToSurfaceWithKey(Graphics::Surface &dstSurface,
const Graphics::Surface &srcSurface, int destX, int destY,
const Common::Rect &subRect, uint32 key) const = 0;
virtual void alignRect(const Graphics::Surface &srcSurface, Common::Rect &rect) const {}
virtual void sync() const {}
enum class ScaleMode {
NONE,
@ -195,12 +200,19 @@ private:
};
int _pendingScreenChange = kPendingScreenChangeNone;
bool _screenModified = false; // double/triple buffering only
byte *_screen[SCREENS] = {}; // for Mfree() purposes only
byte *_screenAligned[SCREENS] = {};
Graphics::Surface _screenSurface;
Common::Rect _modifiedScreenRect; // direct rendering only
bool _screenModified = false; // double/triple buffering only
Common::Array<Common::Rect> _modifiedChunkyRects;
byte *_overlayScreen = nullptr; // for Mfree() purposes only
Graphics::Surface _screenOverlaySurface;
bool _overlayVisible = false;
Graphics::Surface _overlaySurface;
Common::Array<Common::Rect> _modifiedOverlayRects;
struct Cursor {

View File

@ -20,15 +20,12 @@
*/
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <mint/cookie.h>
#include <mint/falcon.h>
#include <mint/osbind.h>
// We use some stdio.h functionality here thus we need to allow some
// symbols. Alternatively, we could simply allow everything by defining
// FORBIDDEN_SYMBOL_ALLOW_ALL
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
@ -51,6 +48,7 @@
#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-superblitter.h"
#include "backends/graphics/atari/atari-graphics-supervidel.h"
#include "backends/graphics/atari/atari-graphics-videl.h"
#include "gui/debugger.h"
@ -115,8 +113,6 @@ void OSystem_Atari::initBackend() {
_startTime = clock();
bool superVidel = VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND;
_timerManager = new DefaultTimerManager();
_savefileManager = new DefaultSaveFileManager("saves");
@ -125,7 +121,7 @@ void OSystem_Atari::initBackend() {
// AtariGraphicsManager needs _eventManager ready
AtariGraphicsManager *atariGraphicsManager;
if (superVidel)
if (hasSuperVidel())
atariGraphicsManager = new AtariSuperVidelManager();
else
atariGraphicsManager = new AtariVidelManager();

View File

@ -24,8 +24,6 @@
#include "backends/modular-backend.h"
#include <time.h>
class OSystem_Atari : public ModularMixerBackend, public ModularGraphicsBackend {
public:
OSystem_Atari();
@ -51,7 +49,7 @@ public:
void update();
private:
clock_t _startTime;
long _startTime;
bool _video_initialized = false;
bool _ikbd_initialized = false;

View File

@ -254,9 +254,7 @@ means that if the SuperVidel is detected, it does the following:
- when SuperVidel FW version >= 9 is detected, the async FIFO buffer is used
instead of the slower sync blitting (where one has to wait for every
rectangle blit to finish). This applies only for chunky buffer -> screen
surfaces copy (as the generic surface copy can't rely on this behavior) but
despite this limitation it sometimes leads to nearly zero-cost rendering
rectangle blit to finish), this sometimes leads to nearly zero-cost rendering
and makes a *huge* difference for 640x480 fullscreen updates.
@ -269,7 +267,7 @@ to avoid unpleasant playing experiences.
Game engines with unexpected performance hit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A typical example from this category is the Gobliins engine (and its
A typical example from this category is the Gobliiins engine (and its
sequels). At first it looks like our machine / backend is doing something
terribly wrong but the truth is it is the engine itself which is doing a lot of
unnecessary redraws and updates, sometimes even before reaching the backend.
@ -383,8 +381,7 @@ Future plans
- avoid loading music/speech files (and thus slowing down everything) if muted
- assembly copy routines for screen/chunky surfaces (even with SuperVidel
present it is not possible to use the SuperBlitter for every surface)
- assembly copy routines when SuperVidel is not present or can't be used
- cached audio/video streams (i.e. don't load only "output_samples" number of
samples but cache, say, 1 second so disk i/o wont be so stressed)
@ -408,6 +405,12 @@ Future plans
- 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
Closing words
—------------

1
configure vendored
View File

@ -3967,6 +3967,7 @@ case $_backend in
;;
atari)
define_in_config_if_yes yes "ATARI"
define_in_config_if_yes yes "USE_SV_BLITTER"
append_var DEFINES "-DDISABLE_LAUNCHERDISPLAY_GRID"
#append_var DEFINES "-DDISABLE_FANCY_THEMES"
#append_var DEFINES "-DDISABLE_SID"

View File

@ -27,15 +27,68 @@
#include <mint/cookie.h>
#include <mint/falcon.h>
#include <mint/trap14.h>
#define ct60_vm(mode, value) (long)trap_14_wwl((short)0xc60e, (short)(mode), (long)(value))
#define ct60_vmalloc(value) ct60_vm(0, value)
#define ct60_vmfree(value) ct60_vm(1, value)
#include "backends/graphics/atari/atari-graphics-superblitter.h"
#include "common/textconsole.h" // error
// bits 26:0
#define SV_BLITTER_SRC1 ((volatile long*)0x80010058)
#define SV_BLITTER_SRC2 ((volatile long*)0x8001005C)
#define SV_BLITTER_DST ((volatile long*)0x80010060)
// The amount of bytes that are to be copied in a horizontal line, minus 1
#define SV_BLITTER_COUNT ((volatile long*)0x80010064)
// The amount of bytes that are to be added to the line start adress after a line has been copied, in order to reach the next one
#define SV_BLITTER_SRC1_OFFSET ((volatile long*)0x80010068)
#define SV_BLITTER_SRC2_OFFSET ((volatile long*)0x8001006C)
#define SV_BLITTER_DST_OFFSET ((volatile long*)0x80010070)
// bits 11:0 - The amount of horizontal lines to do
#define SV_BLITTER_MASK_AND_LINES ((volatile long*)0x80010074)
// bit 0 - busy / start
// bits 4:1 - blit mode
#define SV_BLITTER_CONTROL ((volatile long*)0x80010078)
// bit 0 - empty (read only)
// bit 1 - full (read only)
// bits 31:0 - data (write only)
#define SV_BLITTER_FIFO ((volatile long*)0x80010080)
static bool isSuperBlitterLocked;
static void syncSuperBlitter() {
// if externally locked, let the owner decide when to sync (unlock)
if (isSuperBlitterLocked)
return;
// while FIFO not empty...
if (superVidelFwVersion >= 9)
while (!(*SV_BLITTER_FIFO & 1));
// while busy blitting...
while (*SV_BLITTER_CONTROL & 1);
}
static inline bool hasMove16() {
long val;
static bool hasMove16 = Getcookie(C__CPU, &val) == C_FOUND && val >= 40;
return hasMove16;
}
void lockSuperBlitter() {
assert(!isSuperBlitterLocked);
isSuperBlitterLocked = true;
}
void unlockSuperBlitter() {
assert(isSuperBlitterLocked);
isSuperBlitterLocked = false;
if (hasSuperVidel())
syncSuperBlitter();
}
namespace Graphics {
constexpr size_t ALIGN = 16; // 16 bytes
@ -53,7 +106,7 @@ void Surface::create(int16 width, int16 height, const PixelFormat &f) {
pitch = (w * format.bytesPerPixel + ALIGN - 1) & (-ALIGN);
if (width && height) {
if (VgetMonitor() == MON_VGA && Getcookie(C_SupV, NULL) == C_FOUND) {
if (hasSuperVidel()) {
pixels = (void *)ct60_vmalloc(height * pitch);
if (!pixels)
@ -97,21 +150,32 @@ void copyBlit(byte *dst, const byte *src,
return;
if (((uintptr)src & 0xFF000000) >= 0xA0000000 && ((uintptr)dst & 0xFF000000) >= 0xA0000000) {
// while busy blitting...
while (*SV_BLITTER_CONTROL & 1);
if (superVidelFwVersion >= 9) {
*SV_BLITTER_FIFO = (long)src; // SV_BLITTER_SRC1
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2
*SV_BLITTER_FIFO = (long)dst; // SV_BLITTER_DST
*SV_BLITTER_FIFO = w * bytesPerPixel - 1; // SV_BLITTER_COUNT
*SV_BLITTER_FIFO = srcPitch; // SV_BLITTER_SRC1_OFFSET
*SV_BLITTER_FIFO = 0x00000000; // SV_BLITTER_SRC2_OFFSET
*SV_BLITTER_FIFO = dstPitch; // SV_BLITTER_DST_OFFSET
*SV_BLITTER_FIFO = h; // SV_BLITTER_MASK_AND_LINES
*SV_BLITTER_FIFO = 0x01; // SV_BLITTER_CONTROL
} else {
// make sure the blitter is idle
while (*SV_BLITTER_CONTROL & 1);
*SV_BLITTER_SRC1 = (long)src;
*SV_BLITTER_SRC2 = 0x00000000;
*SV_BLITTER_DST = (long)dst;
*SV_BLITTER_COUNT = w * bytesPerPixel - 1;
*SV_BLITTER_SRC1_OFFSET = srcPitch;
*SV_BLITTER_SRC2_OFFSET = 0x00000000;
*SV_BLITTER_DST_OFFSET = dstPitch;
*SV_BLITTER_MASK_AND_LINES = h;
*SV_BLITTER_CONTROL = 0x01;
*SV_BLITTER_SRC1 = (long)src;
*SV_BLITTER_SRC2 = 0x00000000;
*SV_BLITTER_DST = (long)dst;
*SV_BLITTER_COUNT = w * bytesPerPixel - 1;
*SV_BLITTER_SRC1_OFFSET = srcPitch;
*SV_BLITTER_SRC2_OFFSET = 0x00000000;
*SV_BLITTER_DST_OFFSET = dstPitch;
*SV_BLITTER_MASK_AND_LINES = h;
*SV_BLITTER_CONTROL = 0x01;
}
// wait until we finish otherwise we may overwrite pixels written manually afterwards
while (*SV_BLITTER_CONTROL & 1);
syncSuperBlitter();
} else if (dstPitch == srcPitch && ((w * bytesPerPixel) == dstPitch)) {
if (hasMove16() && ((uintptr)src & (ALIGN - 1)) == 0 && ((uintptr)dst & (ALIGN - 1)) == 0) {
__asm__ volatile(

View File

@ -25,7 +25,7 @@
namespace Graphics {
// see graphics/blit-atari.cpp, Atari Falcon's SuperVidel addon allows accelerated blitting
#ifndef ATARI
#ifndef USE_SV_BLITTER
// Function to blit a rect
void copyBlit(byte *dst, const byte *src,
const uint dstPitch, const uint srcPitch,

View File

@ -63,7 +63,7 @@ MODULE_OBJS += \
scaler/downscalerARM.o
endif
ifdef ATARI
ifdef USE_SV_BLITTER
MODULE_OBJS += \
blit-atari.o
endif

View File

@ -64,7 +64,7 @@ void Surface::drawThickLine(int x0, int y0, int x1, int y1, int penX, int penY,
}
// see graphics/blit-atari.cpp, Atari Falcon's SuperVidel addon allows accelerated blitting
#ifndef ATARI
#ifndef USE_SV_BLITTER
void Surface::create(int16 width, int16 height, const PixelFormat &f) {
assert(width >= 0 && height >= 0);
free();