mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
BACKENDS: ATARI: Final screen resolution changes
- seamless resolution/palette switching (at least in theory, it still isn't artifact-free, no clue why) - bugfixes (shake offset, some s_screenSurf corner cases) - simplification the triple-buffering code
This commit is contained in:
@@ -50,13 +50,11 @@ static const Graphics::PixelFormat PIXELFORMAT_CLUT8 = Graphics::PixelFormat::cr
|
||||
static const Graphics::PixelFormat PIXELFORMAT_RGB332 = Graphics::PixelFormat(1, 3, 3, 2, 0, 5, 2, 0, 0);
|
||||
static const Graphics::PixelFormat PIXELFORMAT_RGB121 = Graphics::PixelFormat(1, 1, 2, 1, 0, 3, 1, 0, 0);
|
||||
|
||||
static bool s_shrinkVidelVisibleArea;
|
||||
|
||||
static void shrinkVidelVisibleArea() {
|
||||
// Active VGA screen area consists of 960 half-lines, i.e. 480 raster lines.
|
||||
// In case of 320x240, the number is still 480 but data is fetched
|
||||
// only for 240 lines so it doesn't make a difference to us.
|
||||
|
||||
#ifdef SCREEN_ACTIVE
|
||||
if (hasSuperVidel()) {
|
||||
const int vOffset = ((480 - 400) / 2) * 2; // *2 because of half-lines
|
||||
|
||||
@@ -77,33 +75,42 @@ static void shrinkVidelVisibleArea() {
|
||||
*((volatile int16*)0xFFFF82A2) = 889;
|
||||
*((volatile int16*)0xFFFF82AC) = 889 + vss;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool s_tt;
|
||||
static int s_shakeXOffset;
|
||||
static int s_shakeYOffset;
|
||||
static int s_aspectRatioCorrectionYOffset;
|
||||
static bool s_shrinkVidelVisibleArea;
|
||||
static bool s_setScreenOffsets;
|
||||
static Graphics::Surface *s_screenSurf;
|
||||
|
||||
static void VblHandler() {
|
||||
if (s_screenSurf) {
|
||||
// for easier querying
|
||||
static Graphics::Surface *surf;
|
||||
|
||||
if (s_screenSurf)
|
||||
surf = s_screenSurf;
|
||||
|
||||
if (s_screenSurf || s_setScreenOffsets) {
|
||||
#ifdef SCREEN_ACTIVE
|
||||
uintptr p = (uintptr)s_screenSurf->getBasePtr(0, MAX_V_SHAKE + s_shakeYOffset + s_aspectRatioCorrectionYOffset);
|
||||
uintptr p = (unsigned long)surf->getBasePtr(0, MAX_V_SHAKE + s_shakeYOffset + s_aspectRatioCorrectionYOffset);
|
||||
|
||||
if (!s_tt) {
|
||||
const int bitsPerPixel = (s_screenSurf->format == PIXELFORMAT_RGB121 ? 4 : 8);
|
||||
const int bitsPerPixel = (surf->format == PIXELFORMAT_RGB121 ? 4 : 8);
|
||||
|
||||
s_shakeXOffset = -s_shakeXOffset;
|
||||
int shakeXOffset = -s_shakeXOffset;
|
||||
|
||||
if (s_shakeXOffset >= 0) {
|
||||
if (shakeXOffset >= 0) {
|
||||
p += MAX_HZ_SHAKE;
|
||||
*((volatile char *)0xFFFF8265) = s_shakeXOffset;
|
||||
*((volatile char *)0xFFFF8265) = shakeXOffset;
|
||||
} else {
|
||||
*((volatile char *)0xFFFF8265) = MAX_HZ_SHAKE + s_shakeXOffset;
|
||||
*((volatile char *)0xFFFF8265) = MAX_HZ_SHAKE + shakeXOffset;
|
||||
}
|
||||
|
||||
// subtract 4 or 8 words if scrolling
|
||||
*((volatile short *)0xFFFF820E) = s_shakeXOffset == 0
|
||||
*((volatile short *)0xFFFF820E) = shakeXOffset == 0
|
||||
? (2 * MAX_HZ_SHAKE * bitsPerPixel / 8) / 2
|
||||
: (2 * MAX_HZ_SHAKE * bitsPerPixel / 8) / 2 - bitsPerPixel;
|
||||
}
|
||||
@@ -116,10 +123,12 @@ static void VblHandler() {
|
||||
*((volatile byte *)0xFFFF820D) = sptr.c[3];
|
||||
#endif
|
||||
s_screenSurf = nullptr;
|
||||
s_setScreenOffsets = false;
|
||||
}
|
||||
|
||||
if (s_shrinkVidelVisibleArea) {
|
||||
shrinkVidelVisibleArea();
|
||||
if (!s_tt)
|
||||
shrinkVidelVisibleArea();
|
||||
s_shrinkVidelVisibleArea = false;
|
||||
}
|
||||
}
|
||||
@@ -189,7 +198,8 @@ void AtariGraphicsShutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
AtariGraphicsManager::AtariGraphicsManager() {
|
||||
AtariGraphicsManager::AtariGraphicsManager()
|
||||
: _pendingScreenChanges(this) {
|
||||
atari_debug("AtariGraphicsManager()");
|
||||
|
||||
enum {
|
||||
@@ -316,14 +326,20 @@ void AtariGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) {
|
||||
if (!hasFeature(f))
|
||||
return;
|
||||
|
||||
// flags must be set to _currentState and _pendingScreenChange here
|
||||
|
||||
// flags must be set to _pendingScreenChanges here
|
||||
|
||||
switch (f) {
|
||||
case OSystem::Feature::kFeatureAspectRatioCorrection:
|
||||
//atari_debug("setFeatureState(kFeatureAspectRatioCorrection): %d", enable);
|
||||
if (_aspectRatioCorrection != enable) {
|
||||
_aspectRatioCorrection = enable;
|
||||
_pendingScreenChange |= kPendingAspectRatioCorrection;
|
||||
|
||||
if (!_overlayVisible) {
|
||||
_pendingScreenChanges.queueAspectRatioCorrection();
|
||||
|
||||
if (!_pendingState.inTransaction)
|
||||
updateScreen();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -350,6 +366,9 @@ bool AtariGraphicsManager::setGraphicsMode(int mode, uint flags) {
|
||||
|
||||
_pendingState.mode = (GraphicsMode)mode;
|
||||
|
||||
if (!_pendingState.inTransaction)
|
||||
return endGFXTransaction() == OSystem::kTransactionSuccess;
|
||||
|
||||
// this doesn't seem to be checked anywhere
|
||||
return true;
|
||||
}
|
||||
@@ -360,25 +379,32 @@ void AtariGraphicsManager::initSize(uint width, uint height, const Graphics::Pix
|
||||
_pendingState.width = width;
|
||||
_pendingState.height = height;
|
||||
_pendingState.format = format ? *format : PIXELFORMAT_CLUT8;
|
||||
|
||||
if (!_pendingState.inTransaction)
|
||||
endGFXTransaction();
|
||||
}
|
||||
|
||||
void AtariGraphicsManager::beginGFXTransaction() {
|
||||
atari_debug("beginGFXTransaction");
|
||||
|
||||
_pendingState = GraphicsState();
|
||||
_pendingScreenChange &= ~kPendingTransaction;
|
||||
_pendingState.inTransaction = true;
|
||||
_pendingScreenChanges.clearTransaction();
|
||||
}
|
||||
|
||||
OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
|
||||
atari_debug("endGFXTransaction");
|
||||
|
||||
_pendingState.inTransaction = false;
|
||||
|
||||
int error = OSystem::TransactionError::kTransactionSuccess;
|
||||
bool hasPendingGraphicsMode = false; // no need to have a global flag
|
||||
|
||||
if (_pendingState.mode != GraphicsMode::Unknown) {
|
||||
if (_pendingState.mode < GraphicsMode::DirectRendering || _pendingState.mode > GraphicsMode::TripleBuffering) {
|
||||
error |= OSystem::TransactionError::kTransactionModeSwitchFailed;
|
||||
} else if (_currentState.mode != _pendingState.mode) {
|
||||
_pendingScreenChange |= kPendingScreenAddress;
|
||||
hasPendingGraphicsMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,8 +414,8 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
|
||||
} else if (_pendingState.width % 16 != 0 && !hasSuperVidel()) {
|
||||
atari_warning("Requested width not divisible by 16, please report");
|
||||
error |= OSystem::TransactionError::kTransactionSizeChangeFailed;
|
||||
} else if (_currentState.width != _pendingState.width || _currentState.height != _pendingState.height) {
|
||||
_pendingScreenChange |= kPendingVideoMode;
|
||||
} else if (_overlayVisible || _currentState.width != _pendingState.width || _currentState.height != _pendingState.height) {
|
||||
_pendingScreenChanges.queueVideoMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -399,35 +425,35 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
|
||||
|
||||
if (error != OSystem::TransactionError::kTransactionSuccess) {
|
||||
atari_warning("endGFXTransaction failed: %02x", (int)error);
|
||||
_pendingScreenChange &= ~kPendingTransaction;
|
||||
_pendingScreenChanges.clearTransaction();
|
||||
return static_cast<OSystem::TransactionError>(error);
|
||||
}
|
||||
|
||||
if (_pendingScreenChange & kPendingScreenAddress)
|
||||
if (hasPendingGraphicsMode)
|
||||
_currentState.mode = _pendingState.mode;
|
||||
|
||||
if ((_pendingScreenChange & kPendingVideoMode)
|
||||
|| (_overlayVisible && _pendingState.width > 0 && _pendingState.height > 0 && _pendingState.format == PIXELFORMAT_CLUT8)) {
|
||||
if (_pendingScreenChanges.videoMode()) {
|
||||
_currentState.width = _pendingState.width;
|
||||
_currentState.height = _pendingState.height;
|
||||
_currentState.format = _pendingState.format;
|
||||
|
||||
if (_overlayVisible) {
|
||||
// that's it, really. updateScreen() will take care of everything.
|
||||
_checkUnalignedPitch = true;
|
||||
_ignoreHideOverlay = false;
|
||||
_overlayVisible = false;
|
||||
// if being in the overlay, reset everything (same as hideOverlay() does)
|
||||
_pendingScreenChange |= kPendingAll;
|
||||
// s_screenSurf will be set below
|
||||
_pendingScreenChanges.queueAll();
|
||||
}
|
||||
} else if (_overlayVisible) {
|
||||
// don't exit overlay unless there is real video mode to be set
|
||||
_ignoreHideOverlay = true;
|
||||
_pendingScreenChange &= ~kPendingTransaction;
|
||||
_pendingState = GraphicsState();
|
||||
_pendingScreenChanges.clearTransaction();
|
||||
return OSystem::kTransactionSuccess;
|
||||
}
|
||||
|
||||
if (_pendingScreenChange & (kPendingScreenAddress | kPendingVideoMode)) {
|
||||
if (_pendingScreenChanges.videoMode() || hasPendingGraphicsMode) {
|
||||
_chunkySurface.init(_currentState.width, _currentState.height, _currentState.width,
|
||||
_chunkySurface.getPixels(), _currentState.format);
|
||||
|
||||
@@ -435,11 +461,14 @@ OSystem::TransactionError AtariGraphicsManager::endGFXTransaction() {
|
||||
_screen[BACK_BUFFER1]->reset(_currentState.width, _currentState.height, 8, true);
|
||||
_screen[BACK_BUFFER2]->reset(_currentState.width, _currentState.height, 8, true);
|
||||
_workScreen = _screen[_currentState.mode <= GraphicsMode::SingleBuffering ? FRONT_BUFFER : BACK_BUFFER1];
|
||||
_pendingScreenChanges.setScreenSurface(&_screen[FRONT_BUFFER]->surf);
|
||||
|
||||
_palette.clear();
|
||||
_pendingScreenChange |= kPendingPalette;
|
||||
_pendingScreenChanges.queuePalette();
|
||||
}
|
||||
|
||||
_pendingState = GraphicsState();
|
||||
|
||||
// apply new screen changes
|
||||
updateScreen();
|
||||
|
||||
@@ -467,7 +496,7 @@ void AtariGraphicsManager::setPalette(const byte *colors, uint start, uint num)
|
||||
}
|
||||
}
|
||||
|
||||
_pendingScreenChange |= kPendingPalette;
|
||||
_pendingScreenChanges.queuePalette();
|
||||
}
|
||||
|
||||
void AtariGraphicsManager::grabPalette(byte *colors, uint start, uint num) const {
|
||||
@@ -622,29 +651,34 @@ void AtariGraphicsManager::updateScreen() {
|
||||
|
||||
_workScreen->clearDirtyRects();
|
||||
|
||||
if (_overlayPending) {
|
||||
atari_debug("Forcing overlay pending state");
|
||||
// must be done here because first updateScreen() is not called from showOverlay()
|
||||
_pendingScreenChanges.queueAll();
|
||||
_overlayPending = false;
|
||||
}
|
||||
|
||||
#ifdef SCREEN_ACTIVE
|
||||
// this assume that the screen surface is not going to be used yet
|
||||
_pendingScreenChanges.applyBeforeVblLock();
|
||||
#endif
|
||||
|
||||
set_sysvar_to_short(vblsem, 0); // lock vbl
|
||||
|
||||
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)
|
||||
// - present BACK_BUFFER1 (as BACK_BUFFER2)
|
||||
// - check if BACK_BUFFER2 has been displayed, if so, switch
|
||||
// BACK_BUFFER2 and FRONT_BUFFER and make previous BACK_BUFFER2 work screen
|
||||
|
||||
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
|
||||
if (s_screenSurf == nullptr) {
|
||||
// BACK_BUFFER2 has been set; guard it from overwriting while presented
|
||||
Screen *tmp = _screen[BACK_BUFFER2];
|
||||
_screen[BACK_BUFFER2] = _screen[FRONT_BUFFER];
|
||||
_screen[FRONT_BUFFER] = tmp;
|
||||
|
||||
old_vbclock = curr_vbclock;
|
||||
}
|
||||
|
||||
// swap back buffers
|
||||
@@ -653,137 +687,28 @@ void AtariGraphicsManager::updateScreen() {
|
||||
_screen[BACK_BUFFER2] = tmp;
|
||||
|
||||
// queue BACK_BUFFER2 with the most recent frame content
|
||||
s_screenSurf = &_screen[BACK_BUFFER2]->surf;
|
||||
|
||||
set_sysvar_to_short(vblsem, 1); // unlock vbl
|
||||
|
||||
_pendingScreenChanges.setScreenSurface(&_screen[BACK_BUFFER2]->surf);
|
||||
_workScreen = _screen[BACK_BUFFER1];
|
||||
// BACK_BUFFER2: now contains finished frame
|
||||
// FRONT_BUFFER is displayed and still contains previously finished frame
|
||||
}
|
||||
|
||||
const int oldPendingScreenChange = _pendingScreenChange;
|
||||
const bool oldAspectRatioCorrection = _aspectRatioCorrection;
|
||||
if (_overlayPending) {
|
||||
atari_debug("Forcing overlay pending state");
|
||||
_aspectRatioCorrection = false;
|
||||
_pendingScreenChange = kPendingAll;
|
||||
}
|
||||
|
||||
bool doShrinkVidelVisibleArea = false;
|
||||
bool doSuperVidelReset = false;
|
||||
if (_pendingScreenChange & kPendingAspectRatioCorrection) {
|
||||
assert(_workScreen->mode != -1);
|
||||
|
||||
if (_aspectRatioCorrection && _currentState.height == 200 && !isOverlayVisible()) {
|
||||
// apply machine-specific aspect ratio correction
|
||||
if (!_vgaMonitor) {
|
||||
_workScreen->mode &= ~PAL;
|
||||
// 60 Hz
|
||||
_workScreen->mode |= NTSC;
|
||||
_pendingScreenChange |= kPendingVideoMode;
|
||||
} else {
|
||||
Screen *screen = _screen[FRONT_BUFFER];
|
||||
s_aspectRatioCorrectionYOffset = (screen->surf.h - 2*MAX_V_SHAKE - screen->offsettedSurf->h) / 2;
|
||||
_pendingScreenChange |= kPendingShakeScreen;
|
||||
|
||||
if (_pendingScreenChange & kPendingVideoMode)
|
||||
doShrinkVidelVisibleArea = true;
|
||||
else
|
||||
s_shrinkVidelVisibleArea = true;
|
||||
}
|
||||
} else {
|
||||
// reset back to default mode
|
||||
if (!_vgaMonitor) {
|
||||
_workScreen->mode &= ~NTSC;
|
||||
// 50 Hz
|
||||
_workScreen->mode |= PAL;
|
||||
_pendingScreenChange |= kPendingVideoMode;
|
||||
} else {
|
||||
s_aspectRatioCorrectionYOffset = 0;
|
||||
s_shrinkVidelVisibleArea = false;
|
||||
|
||||
if (hasSuperVidel())
|
||||
doSuperVidelReset = true;
|
||||
_pendingScreenChange |= kPendingVideoMode;
|
||||
}
|
||||
}
|
||||
|
||||
_pendingScreenChange &= ~kPendingAspectRatioCorrection;
|
||||
}
|
||||
|
||||
#ifdef SCREEN_ACTIVE
|
||||
if (_pendingScreenChange & kPendingVideoMode) {
|
||||
if (_workScreen->rez != -1) {
|
||||
// unfortunately this reinitializes VDI, too
|
||||
Setscreen(SCR_NOCHANGE, SCR_NOCHANGE, _workScreen->rez);
|
||||
|
||||
// strictly speaking, this is necessary only if kScreenAddress is set but makes code easier
|
||||
static uint16 black[256];
|
||||
// Vsync(); // done by Setscreen() above
|
||||
EsetPalette(0, isOverlayVisible() ? 16 : 256, black);
|
||||
} else if (_workScreen->mode != -1) {
|
||||
// VsetMode() must be called first: it resets all hz/v, scrolling and line width registers
|
||||
// so even if kScreenAddress wasn't scheduled, we have to set new s_screenSurf to refresh them
|
||||
static _RGB black[256];
|
||||
VsetRGB(0, 256, black);
|
||||
// Vsync(); // done by (either) VsetMode() below
|
||||
|
||||
if (doSuperVidelReset) {
|
||||
VsetMode(SVEXT | SVEXT_BASERES(0) | COL80 | BPS8C); // resync to proper 640x480
|
||||
doSuperVidelReset = false;
|
||||
}
|
||||
|
||||
atari_debug("VsetMode: %04x", _workScreen->mode);
|
||||
VsetMode(_workScreen->mode);
|
||||
}
|
||||
|
||||
// due to implied Vsync() above
|
||||
assert(s_screenSurf == nullptr);
|
||||
|
||||
// refresh Videl register settings
|
||||
s_screenSurf = isOverlayVisible() ? &_screen[OVERLAY_BUFFER]->surf : &_screen[FRONT_BUFFER]->surf;
|
||||
s_shrinkVidelVisibleArea = doShrinkVidelVisibleArea;
|
||||
|
||||
// keep kVideoMode for resetting the palette later
|
||||
_pendingScreenChange &= ~(kPendingScreenAddress | kPendingShakeScreen);
|
||||
}
|
||||
|
||||
if (_pendingScreenChange & kPendingScreenAddress) {
|
||||
// takes effect in the nearest VBL interrupt but we always wait for Vsync() in this case
|
||||
Vsync();
|
||||
assert(s_screenSurf == nullptr);
|
||||
|
||||
s_screenSurf = isOverlayVisible() ? &_screen[OVERLAY_BUFFER]->surf : &_screen[FRONT_BUFFER]->surf;
|
||||
_pendingScreenChange &= ~kPendingScreenAddress;
|
||||
}
|
||||
|
||||
if (_pendingScreenChange & kPendingShakeScreen) {
|
||||
// takes effect in the nearest VBL interrupt
|
||||
if (!s_screenSurf)
|
||||
s_screenSurf = isOverlayVisible() ? &_screen[OVERLAY_BUFFER]->surf : &_screen[FRONT_BUFFER]->surf;
|
||||
_pendingScreenChange &= ~kPendingShakeScreen;
|
||||
}
|
||||
|
||||
if (_pendingScreenChange & (kPendingVideoMode | kPendingPalette)) {
|
||||
if (!_tt) {
|
||||
// takes effect in the nearest VBL interrupt
|
||||
VsetRGB(0, isOverlayVisible() ? getOverlayPaletteSize() : 256, _workScreen->palette->falcon);
|
||||
} else {
|
||||
// takes effect immediatelly (it's possible that Vsync() hasn't been called: that's expected,
|
||||
// don't cripple framerate only for a palette change)
|
||||
EsetPalette(0, isOverlayVisible() ? getOverlayPaletteSize() : 256, _workScreen->palette->tt);
|
||||
}
|
||||
_pendingScreenChange &= ~(kPendingVideoMode | kPendingPalette);
|
||||
}
|
||||
_pendingScreenChanges.applyAfterVblLock();
|
||||
#endif
|
||||
|
||||
if (_overlayPending) {
|
||||
_aspectRatioCorrection = oldAspectRatioCorrection;
|
||||
_pendingScreenChange = oldPendingScreenChange;
|
||||
_overlayPending = false;
|
||||
if (_pendingScreenChanges.screenSurface()) {
|
||||
s_screenSurf = _pendingScreenChanges.screenSurface();
|
||||
_pendingScreenChanges.setScreenSurface(nullptr);
|
||||
}
|
||||
|
||||
if (_pendingScreenChanges.aspectRatioCorrectionYOffset().second)
|
||||
s_aspectRatioCorrectionYOffset = _pendingScreenChanges.aspectRatioCorrectionYOffset().first;
|
||||
if (_pendingScreenChanges.screenOffsets().second)
|
||||
s_setScreenOffsets = _pendingScreenChanges.screenOffsets().first;
|
||||
if (_pendingScreenChanges.shrinkVidelVisibleArea().second)
|
||||
s_shrinkVidelVisibleArea = _pendingScreenChanges.shrinkVidelVisibleArea().first;
|
||||
|
||||
set_sysvar_to_short(vblsem, 1); // unlock vbl
|
||||
|
||||
//atari_debug("end of updateScreen");
|
||||
}
|
||||
|
||||
@@ -798,7 +723,7 @@ void AtariGraphicsManager::setShakePos(int shakeXOffset, int shakeYOffset) {
|
||||
s_shakeYOffset = shakeYOffset;
|
||||
}
|
||||
|
||||
_pendingScreenChange |= kPendingShakeScreen;
|
||||
_pendingScreenChanges.queueShakeScreen();
|
||||
}
|
||||
|
||||
void AtariGraphicsManager::showOverlay(bool inGUI) {
|
||||
@@ -813,13 +738,17 @@ void AtariGraphicsManager::showOverlay(bool inGUI) {
|
||||
|
||||
_oldWorkScreen = _workScreen;
|
||||
_workScreen = _screen[OVERLAY_BUFFER];
|
||||
_pendingScreenChanges.setScreenSurface(&_workScreen->surf);
|
||||
|
||||
// do not cache dirtyRects and oldCursorRect
|
||||
_workScreen->reset(getOverlayWidth(), getOverlayHeight(), getBitsPerPixel(getOverlayFormat()), false);
|
||||
|
||||
_overlayVisible = true;
|
||||
|
||||
assert(_pendingScreenChange == kPendingNone);
|
||||
if (!_pendingScreenChanges.empty()) {
|
||||
warning("showOverlay: _pendingScreenChanges is %02x", _pendingScreenChanges.get());
|
||||
}
|
||||
//_pendingScreenChanges.queueAll(); // must be called in updateScreen() ...
|
||||
_overlayPending = true;
|
||||
updateScreen();
|
||||
}
|
||||
@@ -837,13 +766,18 @@ void AtariGraphicsManager::hideOverlay() {
|
||||
return;
|
||||
}
|
||||
|
||||
// BACK_BUFFER2 is intentional: regardless of the state before calling showOverlay(),
|
||||
// this always contains the next desired frame buffer to show
|
||||
_pendingScreenChanges.setScreenSurface(&_screen[_currentState.mode == GraphicsMode::TripleBuffering ? BACK_BUFFER2 : FRONT_BUFFER]->surf);
|
||||
_workScreen = _oldWorkScreen;
|
||||
_oldWorkScreen = nullptr;
|
||||
|
||||
_overlayVisible = false;
|
||||
|
||||
assert(_pendingScreenChange == kPendingNone);
|
||||
_pendingScreenChange = kPendingAll;
|
||||
if (!_pendingScreenChanges.empty()) {
|
||||
warning("hideOverlay: _pendingScreenChanges is %02x", _pendingScreenChanges.get());
|
||||
}
|
||||
_pendingScreenChanges.queueAll();
|
||||
updateScreen();
|
||||
}
|
||||
|
||||
@@ -1046,9 +980,12 @@ bool AtariGraphicsManager::notifyEvent(const Common::Event &event) {
|
||||
case kActionToggleAspectRatioCorrection:
|
||||
if (hasFeature(OSystem::Feature::kFeatureAspectRatioCorrection)) {
|
||||
_aspectRatioCorrection = !_aspectRatioCorrection;
|
||||
_pendingScreenChange |= kPendingAspectRatioCorrection;
|
||||
|
||||
updateScreen();
|
||||
if (!_overlayVisible) {
|
||||
_pendingScreenChanges.queueAspectRatioCorrection();
|
||||
|
||||
updateScreen();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@@ -1084,6 +1021,7 @@ void AtariGraphicsManager::allocateSurfaces() {
|
||||
// overlay is the default screen upon start
|
||||
_workScreen = _screen[OVERLAY_BUFFER] = new Screen(this, getOverlayWidth(), getOverlayHeight(), getOverlayFormat(), &_overlayPalette);
|
||||
_workScreen->reset(getOverlayWidth(), getOverlayHeight(), getBitsPerPixel(getOverlayFormat()), true);
|
||||
_pendingScreenChanges.setScreenSurface(&_workScreen->surf);
|
||||
|
||||
_chunkySurface.create(getMaximumScreenWidth(), getMaximumScreenHeight(), PIXELFORMAT_CLUT8);
|
||||
_overlaySurface.create(getOverlayWidth(), getOverlayHeight(), getOverlayFormat());
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "atari-cursor.h"
|
||||
#include "atari-pendingscreenchanges.h"
|
||||
#include "atari-screen.h"
|
||||
|
||||
#define MAX_HZ_SHAKE 16 // Falcon only
|
||||
@@ -38,6 +39,7 @@
|
||||
|
||||
class AtariGraphicsManager : public GraphicsManager, Common::EventObserver {
|
||||
friend class Cursor;
|
||||
friend class PendingScreenChanges;
|
||||
friend class Screen;
|
||||
|
||||
public:
|
||||
@@ -178,12 +180,14 @@ private:
|
||||
|
||||
struct GraphicsState {
|
||||
GraphicsState()
|
||||
: mode(GraphicsMode::Unknown)
|
||||
: inTransaction(false)
|
||||
, mode(GraphicsMode::Unknown)
|
||||
, width(0)
|
||||
, height(0)
|
||||
, format(Graphics::PixelFormat()) {
|
||||
}
|
||||
|
||||
bool inTransaction;
|
||||
GraphicsMode mode;
|
||||
int width;
|
||||
int height;
|
||||
@@ -195,17 +199,7 @@ private:
|
||||
// feature flags
|
||||
bool _aspectRatioCorrection = false;
|
||||
|
||||
enum PendingScreenChange {
|
||||
kPendingNone = 0,
|
||||
kPendingVideoMode = 1<<0,
|
||||
kPendingScreenAddress = 1<<1,
|
||||
kPendingAspectRatioCorrection = 1<<2,
|
||||
kPendingPalette = 1<<3,
|
||||
kPendingShakeScreen = 1<<4,
|
||||
kPendingTransaction = kPendingVideoMode | kPendingScreenAddress | kPendingAspectRatioCorrection,
|
||||
kPendingAll = kPendingTransaction | kPendingPalette | kPendingShakeScreen
|
||||
};
|
||||
int _pendingScreenChange = kPendingNone;
|
||||
PendingScreenChanges _pendingScreenChanges;
|
||||
|
||||
enum {
|
||||
FRONT_BUFFER,
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "atari-pendingscreenchanges.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <mint/falcon.h>
|
||||
|
||||
#include "backends/platform/atari/atari-debug.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "atari-graphics.h"
|
||||
#include "atari-graphics-superblitter.h"
|
||||
|
||||
void PendingScreenChanges::queueAll() {
|
||||
_changes |= kAll;
|
||||
|
||||
if (_manager->_tt)
|
||||
_changes &= ~kAspectRatioCorrection;
|
||||
}
|
||||
|
||||
/*
|
||||
* VsetRGB() - stores the palette in a buffer and applyBeforeVblLock in nearest VBL
|
||||
* EsetPalette() - immediatelly applies the palette
|
||||
* (V)SetScreen() - immediatelly sets physbase/logbase but explicitly calls Vsync() for resolution changes
|
||||
* VsetMode() - explicitly calls Vsync()
|
||||
*/
|
||||
|
||||
void PendingScreenChanges::applyBeforeVblLock() {
|
||||
_resetSuperVidel = false;
|
||||
_switchToBlackPalette = (_changes & kVideoMode);
|
||||
|
||||
_aspectRatioCorrectionYOffset.second = false;
|
||||
_setScreenOffsets.second = false;
|
||||
_shrinkVidelVisibleArea.second = false;
|
||||
|
||||
if (_changes & kAspectRatioCorrection) {
|
||||
processAspectRatioCorrection();
|
||||
_changes &= ~kAspectRatioCorrection;
|
||||
}
|
||||
|
||||
_switchToBlackPalette |= _resetSuperVidel;
|
||||
|
||||
if (_changes & kVideoMode) {
|
||||
processVideoMode();
|
||||
// don't reset kVideoMode yet
|
||||
}
|
||||
}
|
||||
|
||||
void PendingScreenChanges::applyAfterVblLock() {
|
||||
// VBL doesn't process new palette nor screen address updates
|
||||
|
||||
if (_changes & kShakeScreen) {
|
||||
_setScreenOffsets = std::make_pair(true, true);
|
||||
_changes &= ~kShakeScreen;
|
||||
}
|
||||
|
||||
// restore current (kVideoMode) or set new (kPalette) palette
|
||||
if (_changes & (kVideoMode | kPalette)) {
|
||||
if (_switchToBlackPalette || (_changes & kPalette)) {
|
||||
if (_manager->_tt) {
|
||||
if (_changes & kPalette)
|
||||
Vsync();
|
||||
EsetPalette(0, _manager->isOverlayVisible() ? _manager->getOverlayPaletteSize() : 256, _manager->_workScreen->palette->tt);
|
||||
} else {
|
||||
VsetRGB(0, _manager->isOverlayVisible() ? _manager->getOverlayPaletteSize() : 256, _manager->_workScreen->palette->falcon);
|
||||
if (_changes & kPalette)
|
||||
Vsync();
|
||||
}
|
||||
}
|
||||
|
||||
_changes &= ~(kVideoMode | kPalette);
|
||||
}
|
||||
|
||||
assert(_changes == kNone);
|
||||
}
|
||||
|
||||
void PendingScreenChanges::processAspectRatioCorrection() {
|
||||
assert(!_manager->_tt);
|
||||
|
||||
if (_manager->_aspectRatioCorrection && _manager->_currentState.height == 200 && !_manager->isOverlayVisible()) {
|
||||
// apply machine-specific aspect ratio correction
|
||||
if (!_manager->_vgaMonitor) {
|
||||
_manager->_workScreen->mode &= ~PAL;
|
||||
// 60 Hz
|
||||
_manager->_workScreen->mode |= NTSC;
|
||||
_changes |= kVideoMode;
|
||||
} else {
|
||||
_aspectRatioCorrectionYOffset =
|
||||
std::make_pair((_manager->_workScreen->surf.h - 2*MAX_V_SHAKE - _manager->_workScreen->offsettedSurf->h) / 2, true);
|
||||
_shrinkVidelVisibleArea = std::make_pair(true, true);
|
||||
}
|
||||
} else {
|
||||
// reset back to default mode
|
||||
if (!_manager->_vgaMonitor) {
|
||||
_manager->_workScreen->mode &= ~NTSC;
|
||||
// 50 Hz
|
||||
_manager->_workScreen->mode |= PAL;
|
||||
_changes |= kVideoMode;
|
||||
} else {
|
||||
_aspectRatioCorrectionYOffset = std::make_pair(0, true);
|
||||
_shrinkVidelVisibleArea = std::make_pair(false, true);
|
||||
|
||||
if (hasSuperVidel())
|
||||
_resetSuperVidel = true;
|
||||
|
||||
// kPendingVideoMode will reset the shrunken Videl area
|
||||
_changes |= kVideoMode;
|
||||
}
|
||||
}
|
||||
|
||||
// for VsetMode() and/or _aspectRatioCorrectionYOffset
|
||||
_setScreenOffsets = std::make_pair(true, true);
|
||||
}
|
||||
|
||||
void PendingScreenChanges::processVideoMode() {
|
||||
// changing video mode implies an additional Vsync(): there's no way to change resolution
|
||||
// and set new screen address (and/or shake offsets etc) in one go
|
||||
if (_manager->_workScreen->rez != -1) {
|
||||
if (_switchToBlackPalette) {
|
||||
static uint16 black[256];
|
||||
EsetPalette(0, _manager->isOverlayVisible() ? _manager->getOverlayPaletteSize() : 256, black);
|
||||
}
|
||||
|
||||
// unfortunately this reinitializes VDI, too
|
||||
Setscreen(SCR_NOCHANGE, SCR_NOCHANGE, _manager->_workScreen->rez);
|
||||
} else if (_manager->_workScreen->mode != -1) {
|
||||
if (_switchToBlackPalette) {
|
||||
static _RGB black[256];
|
||||
VsetRGB(0, _manager->isOverlayVisible() ? _manager->getOverlayPaletteSize() : 256, black);
|
||||
}
|
||||
|
||||
// VsetMode() must be called first: it resets all hz/v, scrolling and line width registers
|
||||
if (_resetSuperVidel)
|
||||
VsetMode(SVEXT | SVEXT_BASERES(0) | COL80 | BPS8C); // resync to proper 640x480
|
||||
|
||||
atari_debug("VsetMode: %04x", _manager->_workScreen->mode);
|
||||
VsetMode(_manager->_workScreen->mode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/* 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_PENDINGSCREENCHANGES_H
|
||||
#define BACKENDS_GRAPHICS_ATARI_PENDINGSCREENCHANGES_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
class AtariGraphicsManager;
|
||||
namespace Graphics {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
class PendingScreenChanges {
|
||||
public:
|
||||
PendingScreenChanges(AtariGraphicsManager *manager)
|
||||
: _manager(manager) {
|
||||
}
|
||||
|
||||
void clearTransaction() {
|
||||
_changes &= ~kTransaction;
|
||||
}
|
||||
|
||||
void setScreenSurface(Graphics::Surface *surface) {
|
||||
_surface = surface;
|
||||
}
|
||||
|
||||
void queueVideoMode() {
|
||||
_changes |= kVideoMode;
|
||||
}
|
||||
void queueAspectRatioCorrection() {
|
||||
_changes |= kAspectRatioCorrection;
|
||||
}
|
||||
void queuePalette() {
|
||||
_changes |= kPalette;
|
||||
}
|
||||
void queueShakeScreen() {
|
||||
_changes |= kShakeScreen;
|
||||
}
|
||||
void queueAll();
|
||||
|
||||
int get() const {
|
||||
return _changes;
|
||||
}
|
||||
|
||||
bool videoMode() const {
|
||||
return _changes & kVideoMode;
|
||||
}
|
||||
bool empty() const {
|
||||
return _changes == kNone;
|
||||
}
|
||||
|
||||
Graphics::Surface *screenSurface() const {
|
||||
return _surface;
|
||||
}
|
||||
const std::pair<int, bool>& aspectRatioCorrectionYOffset() const {
|
||||
return _aspectRatioCorrectionYOffset;
|
||||
}
|
||||
const std::pair<bool, bool>& screenOffsets() const {
|
||||
return _setScreenOffsets;
|
||||
}
|
||||
const std::pair<bool, bool>& shrinkVidelVisibleArea() const {
|
||||
return _shrinkVidelVisibleArea;
|
||||
}
|
||||
|
||||
void applyBeforeVblLock();
|
||||
void applyAfterVblLock();
|
||||
|
||||
private:
|
||||
void processAspectRatioCorrection();
|
||||
void processVideoMode();
|
||||
|
||||
enum Change {
|
||||
kNone = 0,
|
||||
kVideoMode = 1<<0,
|
||||
kAspectRatioCorrection = 1<<1,
|
||||
kPalette = 1<<2,
|
||||
kShakeScreen = 1<<3,
|
||||
kTransaction = kVideoMode | kAspectRatioCorrection,
|
||||
kAll = kTransaction | kPalette | kShakeScreen
|
||||
};
|
||||
int _changes = kNone;
|
||||
|
||||
AtariGraphicsManager *_manager;
|
||||
|
||||
Graphics::Surface *_surface = nullptr;
|
||||
|
||||
bool _resetSuperVidel;
|
||||
bool _switchToBlackPalette;
|
||||
|
||||
// <value, set> ... std::optional would be so much better!
|
||||
std::pair<int, bool> _aspectRatioCorrectionYOffset;
|
||||
std::pair<bool, bool> _setScreenOffsets;
|
||||
std::pair<bool, bool> _shrinkVidelVisibleArea;
|
||||
|
||||
};
|
||||
|
||||
#endif // ATARI-PENDINGSCREENCHANGES_H
|
||||
@@ -370,6 +370,7 @@ MODULE_OBJS += \
|
||||
graphics/atari/atari-cursor.o \
|
||||
graphics/atari/atari-graphics.o \
|
||||
graphics/atari/atari-graphics-asm.o \
|
||||
graphics/atari/atari-pendingscreenchanges.o \
|
||||
graphics/atari/atari-screen.o \
|
||||
mixer/atari/atari-mixer.o
|
||||
endif
|
||||
|
||||
Reference in New Issue
Block a user