From 5a0556f09ca89886fda55d333745a672ea14e022 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Fri, 14 Nov 2008 22:08:10 +0000 Subject: Committed my patch #2123680 "SDL: Backend transaction / rollback support". svn-id: r35062 --- backends/platform/sdl/events.cpp | 10 +- backends/platform/sdl/graphics.cpp | 541 +++++++++++++++++++------------------ backends/platform/sdl/sdl.cpp | 26 +- backends/platform/sdl/sdl.h | 54 ++-- 4 files changed, 321 insertions(+), 310 deletions(-) (limited to 'backends/platform') diff --git a/backends/platform/sdl/events.cpp b/backends/platform/sdl/events.cpp index a7a9251678..bcaa0e5a0a 100644 --- a/backends/platform/sdl/events.cpp +++ b/backends/platform/sdl/events.cpp @@ -77,9 +77,9 @@ void OSystem_SDL::fillMouseEvent(Common::Event &event, int x, int y) { // Adjust for the screen scaling if (!_overlayVisible) { - event.mouse.x /= _scaleFactor; - event.mouse.y /= _scaleFactor; - if (_adjustAspectRatio) + event.mouse.x /= _videoMode.scaleFactor; + event.mouse.y /= _videoMode.scaleFactor; + if (_videoMode.aspectRatio) event.mouse.y = aspect2Real(event.mouse.y); } } @@ -196,10 +196,10 @@ bool OSystem_SDL::pollEvent(Common::Event &event) { if (b == Common::KBD_ALT && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_KP_ENTER)) { beginGFXTransaction(); - setFullscreenMode(!_fullscreen); + setFullscreenMode(!_videoMode.fullscreen); endGFXTransaction(); #ifdef USE_OSD - if (_fullscreen) + if (_videoMode.fullscreen) displayMessageOnOSD("Fullscreen mode"); else displayMessageOnOSD("Windowed mode"); diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp index c2a6285001..32ea425f8c 100644 --- a/backends/platform/sdl/graphics.cpp +++ b/backends/platform/sdl/graphics.cpp @@ -49,7 +49,7 @@ static const OSystem::GraphicsMode s_supportedGraphicsModes[] = { }; // Table of relative scalers magnitudes -// [definedScale - 1][_scaleFactor - 1] +// [definedScale - 1][scaleFactor - 1] static ScalerProc *scalersMagn[3][3] = { #ifndef DISABLE_SCALERS { Normal1x, AdvMame2x, AdvMame3x }, @@ -86,122 +86,146 @@ int OSystem_SDL::getDefaultGraphicsMode() const { } void OSystem_SDL::beginGFXTransaction(void) { - assert (_transactionMode == kTransactionNone); + assert(_transactionMode == kTransactionNone); _transactionMode = kTransactionActive; - _transactionDetails.modeChanged = false; _transactionDetails.sizeChanged = false; - _transactionDetails.arChanged = false; - _transactionDetails.fsChanged = false; _transactionDetails.needHotswap = false; _transactionDetails.needUpdatescreen = false; - _transactionDetails.needUnload = false; _transactionDetails.normal1xScaler = false; + + _oldVideoMode = _videoMode; } -void OSystem_SDL::endGFXTransaction(void) { - // for each engine we run initCommonGFX() as first thing in the transaction - // and initSize() is called later. If user runs launcher at 320x200 with - // 2x overlay, setting to Nomral1x sclaler in that case will be suppressed - // and backend is forced to 2x - // - // This leads to bad results such as 1280x960 window for 640x480 engines. - // To prevent that we rerun setGraphicsMode() if there was 1x scaler request - if (_transactionDetails.normal1xScaler) - setGraphicsMode(GFX_NORMAL); +OSystem::TransactionError OSystem_SDL::endGFXTransaction(void) { + int errors = kTransactionSuccess; + + assert(_transactionMode != kTransactionNone); - assert (_transactionMode == kTransactionActive); + if (_transactionMode == kTransactionRollback) { + if (_videoMode.fullscreen != _oldVideoMode.fullscreen) { + errors |= kTransactionFullscreenFailed; - _transactionMode = kTransactionCommit; - if (_transactionDetails.modeChanged) - setGraphicsMode(_transactionDetails.mode); + _videoMode.fullscreen = _oldVideoMode.fullscreen; + } else if (_videoMode.aspectRatio != _oldVideoMode.aspectRatio) { + errors |= kTransactionAspectRatioFailed; - if (_transactionDetails.sizeChanged) - initSize(_transactionDetails.w, _transactionDetails.h); + _videoMode.aspectRatio = _oldVideoMode.aspectRatio; + } else if (_videoMode.mode != _oldVideoMode.mode) { + errors |= kTransactionModeSwitchFailed; - if (_transactionDetails.arChanged) - setAspectRatioCorrection(_transactionDetails.ar); + _videoMode.mode = _oldVideoMode.mode; + _videoMode.scaleFactor = _oldVideoMode.scaleFactor; + } else if (_videoMode.screenWidth != _oldVideoMode.screenWidth || _videoMode.screenHeight != _oldVideoMode.screenHeight) { + errors |= kTransactionSizeChangeFailed; + + _videoMode.screenWidth = _oldVideoMode.screenWidth; + _videoMode.screenHeight = _oldVideoMode.screenHeight; + _videoMode.overlayWidth = _oldVideoMode.overlayWidth; + _videoMode.overlayHeight = _oldVideoMode.overlayHeight; + } + + if (_videoMode.fullscreen == _oldVideoMode.fullscreen && + _videoMode.aspectRatio == _oldVideoMode.aspectRatio && + _videoMode.mode == _oldVideoMode.mode && + _videoMode.screenWidth == _oldVideoMode.screenWidth && + _videoMode.screenHeight == _oldVideoMode.screenHeight) { + + // Our new video mode would now be exactly the same as the + // old one. Since we still can not assume SDL_SetVideoMode + // to be working fine, we need to invalidate the old video + // mode, so loadGFXMode would error out properly. + _oldVideoMode.setup = false; + } + } - if (_transactionDetails.needUnload) { + if (_transactionDetails.sizeChanged) { unloadGFXMode(); - loadGFXMode(); - clearOverlay(); - } else { - if (!_transactionDetails.fsChanged) { - if (_transactionDetails.needHotswap) - hotswapGFXMode(); - else if (_transactionDetails.needUpdatescreen) + if (!loadGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + setGraphicsModeIntern(); + clearOverlay(); + + _videoMode.setup = true; + _modeChanged = true; + } + } else if (_transactionDetails.needHotswap) { + setGraphicsModeIntern(); + if (!hotswapGFXMode()) { + if (_oldVideoMode.setup) { + _transactionMode = kTransactionRollback; + errors |= endGFXTransaction(); + } + } else { + _videoMode.setup = true; + _modeChanged = true; + + if (_transactionDetails.needUpdatescreen) internUpdateScreen(); } } - if (_transactionDetails.fsChanged) - setFullscreenMode(_transactionDetails.fs); - _transactionMode = kTransactionNone; + return (TransactionError)errors; } bool OSystem_SDL::setGraphicsMode(int mode) { Common::StackLock lock(_graphicsMutex); + assert(_transactionMode == kTransactionActive); + + if (_oldVideoMode.setup && _oldVideoMode.mode == mode) + return true; + int newScaleFactor = 1; - ScalerProc *newScalerProc; switch(mode) { case GFX_NORMAL: newScaleFactor = 1; - newScalerProc = Normal1x; break; #ifndef DISABLE_SCALERS case GFX_DOUBLESIZE: newScaleFactor = 2; - newScalerProc = Normal2x; break; case GFX_TRIPLESIZE: newScaleFactor = 3; - newScalerProc = Normal3x; break; case GFX_2XSAI: newScaleFactor = 2; - newScalerProc = _2xSaI; break; case GFX_SUPER2XSAI: newScaleFactor = 2; - newScalerProc = Super2xSaI; break; case GFX_SUPEREAGLE: newScaleFactor = 2; - newScalerProc = SuperEagle; break; case GFX_ADVMAME2X: newScaleFactor = 2; - newScalerProc = AdvMame2x; break; case GFX_ADVMAME3X: newScaleFactor = 3; - newScalerProc = AdvMame3x; break; #ifndef DISABLE_HQ_SCALERS case GFX_HQ2X: newScaleFactor = 2; - newScalerProc = HQ2x; break; case GFX_HQ3X: newScaleFactor = 3; - newScalerProc = HQ3x; break; #endif case GFX_TV2X: newScaleFactor = 2; - newScalerProc = TV2x; break; case GFX_DOTMATRIX: newScaleFactor = 2; - newScalerProc = DotMatrix; break; #endif // DISABLE_SCALERS @@ -211,47 +235,81 @@ bool OSystem_SDL::setGraphicsMode(int mode) { } _transactionDetails.normal1xScaler = (mode == GFX_NORMAL); + if (_oldVideoMode.setup && _oldVideoMode.scaleFactor != newScaleFactor) + _transactionDetails.needHotswap = true; - _mode = mode; - _scalerProc = newScalerProc; + _transactionDetails.needUpdatescreen = true; - if (_transactionMode == kTransactionActive) { - _transactionDetails.mode = mode; - _transactionDetails.modeChanged = true; + _videoMode.mode = mode; + _videoMode.scaleFactor = newScaleFactor; - if (newScaleFactor != _scaleFactor) { - _transactionDetails.needHotswap = true; - _scaleFactor = newScaleFactor; - } + return true; +} - _transactionDetails.needUpdatescreen = true; +void OSystem_SDL::setGraphicsModeIntern() { + Common::StackLock lock(_graphicsMutex); + ScalerProc *newScalerProc = 0; - return true; - } + switch (_videoMode.mode) { + case GFX_NORMAL: + newScalerProc = Normal1x; + break; +#ifndef DISABLE_SCALERS + case GFX_DOUBLESIZE: + newScalerProc = Normal2x; + break; + case GFX_TRIPLESIZE: + newScalerProc = Normal3x; + break; - // NOTE: This should not be executed at transaction commit - // Otherwise there is some unsolicited setGraphicsMode() call - // which should be properly removed - if (newScaleFactor != _scaleFactor) { - assert(_transactionMode != kTransactionCommit); + case GFX_2XSAI: + newScalerProc = _2xSaI; + break; + case GFX_SUPER2XSAI: + newScalerProc = Super2xSaI; + break; + case GFX_SUPEREAGLE: + newScalerProc = SuperEagle; + break; + case GFX_ADVMAME2X: + newScalerProc = AdvMame2x; + break; + case GFX_ADVMAME3X: + newScalerProc = AdvMame3x; + break; +#ifndef DISABLE_HQ_SCALERS + case GFX_HQ2X: + newScalerProc = HQ2x; + break; + case GFX_HQ3X: + newScalerProc = HQ3x; + break; +#endif + case GFX_TV2X: + newScalerProc = TV2x; + break; + case GFX_DOTMATRIX: + newScalerProc = DotMatrix; + break; +#endif // DISABLE_SCALERS - _scaleFactor = newScaleFactor; - hotswapGFXMode(); + default: + error("Unknown gfx mode %d", _videoMode.mode); } - // Determine the "scaler type", i.e. essentially an index into the - // s_gfxModeSwitchTable array defined in events.cpp. - if (_mode != GFX_NORMAL) { + _scalerProc = newScalerProc; + + if (_videoMode.mode != GFX_NORMAL) { for (int i = 0; i < ARRAYSIZE(s_gfxModeSwitchTable); i++) { - if (s_gfxModeSwitchTable[i][1] == _mode || s_gfxModeSwitchTable[i][2] == _mode) { + if (s_gfxModeSwitchTable[i][1] == _videoMode.mode || s_gfxModeSwitchTable[i][2] == _videoMode.mode) { _scalerType = i; break; } } } - if (!_screen) - return true; + if (!_screen || !_hwscreen) + return; // Blit everything to the screen _forceFull = true; @@ -259,81 +317,58 @@ bool OSystem_SDL::setGraphicsMode(int mode) { // Even if the old and new scale factors are the same, we may have a // different scaler for the cursor now. blitCursor(); - - if (_transactionMode != kTransactionCommit) - internUpdateScreen(); - - // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later - _modeChanged = true; - - return true; } int OSystem_SDL::getGraphicsMode() const { assert (_transactionMode == kTransactionNone); - return _mode; + return _videoMode.mode; } void OSystem_SDL::initSize(uint w, uint h) { + assert(_transactionMode == kTransactionActive); + // Avoid redundant res changes - if ((int)w == _screenWidth && (int)h == _screenHeight && - _transactionMode != kTransactionCommit) + if ((int)w == _videoMode.screenWidth && (int)h == _videoMode.screenHeight) return; - _screenWidth = w; - _screenHeight = h; + _videoMode.screenWidth = w; + _videoMode.screenHeight = h; - _cksumNum = (_screenWidth * _screenHeight / (8 * 8)); - - if (_transactionMode == kTransactionActive) { - _transactionDetails.w = w; - _transactionDetails.h = h; - _transactionDetails.sizeChanged = true; + _cksumNum = (w * h / (8 * 8)); - _transactionDetails.needUnload = true; - - return; - } + _transactionDetails.sizeChanged = true; free(_dirtyChecksums); _dirtyChecksums = (uint32 *)calloc(_cksumNum * 2, sizeof(uint32)); - - if (_transactionMode != kTransactionCommit) { - unloadGFXMode(); - loadGFXMode(); - - // if initSize() gets called in the middle, overlay is not transparent - clearOverlay(); - } } -void OSystem_SDL::loadGFXMode() { +bool OSystem_SDL::loadGFXMode() { assert(_inited); _forceFull = true; int hwW, hwH; #ifndef __MAEMO__ - _overlayWidth = _screenWidth * _scaleFactor; - _overlayHeight = _screenHeight * _scaleFactor; + _videoMode.overlayWidth = _videoMode.screenWidth * _videoMode.scaleFactor; + _videoMode.overlayHeight = _videoMode.screenHeight * _videoMode.scaleFactor; - if (_screenHeight != 200 && _screenHeight != 400) - _adjustAspectRatio = false; + if (_videoMode.screenHeight != 200 && _videoMode.screenHeight != 400) + _videoMode.aspectRatio = false; - if (_adjustAspectRatio) - _overlayHeight = real2Aspect(_overlayHeight); + if (_videoMode.aspectRatio) + _videoMode.overlayHeight = real2Aspect(_videoMode.overlayHeight); - hwW = _screenWidth * _scaleFactor; + hwW = _videoMode.screenWidth * _videoMode.scaleFactor; hwH = effectiveScreenHeight(); #else - hwW = _overlayWidth; - hwH = _overlayHeight; + hwW = _videoMode.overlayWidth; + hwH = _videoMode.overlayHeight; #endif // // Create the surface that contains the 8 bit game data // - _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth, _screenHeight, 8, 0, 0, 0, 0); + _screen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth, _videoMode.screenHeight, 8, 0, 0, 0, 0); if (_screen == NULL) error("allocating _screen failed"); @@ -342,27 +377,18 @@ void OSystem_SDL::loadGFXMode() { // _hwscreen = SDL_SetVideoMode(hwW, hwH, 16, - _fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE + _videoMode.fullscreen ? (SDL_FULLSCREEN|SDL_SWSURFACE) : SDL_SWSURFACE ); if (_hwscreen == NULL) { // DON'T use error(), as this tries to bring up the debug // console, which WON'T WORK now that _hwscreen is hosed. - // FIXME: We should be able to continue the game without - // shutting down or bringing up the debug console, but at - // this point we've already screwed up all our member vars. - // We need to find a way to call SDL_SetVideoMode *before* - // that happens and revert to all the old settings if we - // can't pull off the switch to the new settings. - // - // Fingolfin says: the "easy" way to do that is not to modify - // the member vars before we are sure everything is fine. Think - // of "transactions, commit, rollback" style... we use local vars - // in place of the member vars, do everything etc. etc.. In case - // of a failure, rollback is trivial. Only if everything worked fine - // do we "commit" the changed values to the member vars. - warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); - quit(); + if (!_oldVideoMode.setup) { + warning("SDL_SetVideoMode says we can't switch to that mode (%s)", SDL_GetError()); + quit(); + } else { + return false; + } } // @@ -376,7 +402,7 @@ void OSystem_SDL::loadGFXMode() { InitScalers(565); // Need some extra bytes around when using 2xSaI - _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _screenWidth + 3, _screenHeight + 3, + _tmpscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + 3, _videoMode.screenHeight + 3, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, @@ -386,7 +412,7 @@ void OSystem_SDL::loadGFXMode() { if (_tmpscreen == NULL) error("allocating _tmpscreen failed"); - _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth, _overlayHeight, + _overlayscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth, _videoMode.overlayHeight, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, @@ -408,7 +434,7 @@ void OSystem_SDL::loadGFXMode() { _overlayFormat.bShift = _overlayscreen->format->Bshift; _overlayFormat.aShift = _overlayscreen->format->Ashift; - _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _overlayWidth + 3, _overlayHeight + 3, + _tmpscreen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.overlayWidth + 3, _videoMode.overlayHeight + 3, 16, _hwscreen->format->Rmask, _hwscreen->format->Gmask, @@ -433,10 +459,12 @@ void OSystem_SDL::loadGFXMode() { #endif // keyboard cursor control, some other better place for it? - _km.x_max = _screenWidth * _scaleFactor - 1; + _km.x_max = _videoMode.screenWidth * _videoMode.scaleFactor - 1; _km.y_max = effectiveScreenHeight() - 1; _km.delay_time = 25; _km.last_time = 0; + + return true; } void OSystem_SDL::unloadGFXMode() { @@ -474,28 +502,37 @@ void OSystem_SDL::unloadGFXMode() { DestroyScalers(); } -void OSystem_SDL::hotswapGFXMode() { +bool OSystem_SDL::hotswapGFXMode() { if (!_screen) - return; + return false; // Keep around the old _screen & _overlayscreen so we can restore the screen data // after the mode switch. SDL_Surface *old_screen = _screen; SDL_Surface *old_overlayscreen = _overlayscreen; + _screen = NULL; + _overlayscreen = NULL; // Release the HW screen surface - SDL_FreeSurface(_hwscreen); + SDL_FreeSurface(_hwscreen); _hwscreen = NULL; - SDL_FreeSurface(_tmpscreen); - SDL_FreeSurface(_tmpscreen2); + SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; + SDL_FreeSurface(_tmpscreen2); _tmpscreen2 = NULL; #ifdef USE_OSD // Release the OSD surface - SDL_FreeSurface(_osdSurface); + SDL_FreeSurface(_osdSurface); _osdSurface = NULL; #endif // Setup the new GFX mode - loadGFXMode(); + if (!loadGFXMode()) { + unloadGFXMode(); + + _screen = old_screen; + _overlayscreen = old_overlayscreen; + + return false; + } // reset palette SDL_SetColors(_screen, _currentPalette, 0, 256); @@ -514,8 +551,7 @@ void OSystem_SDL::hotswapGFXMode() { // Blit everything to the screen internUpdateScreen(); - // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later - _modeChanged = true; + return true; } void OSystem_SDL::updateScreen() { @@ -539,9 +575,9 @@ void OSystem_SDL::internUpdateScreen() { // If the shake position changed, fill the dirty area with blackness if (_currentShakePos != _newShakePos) { - SDL_Rect blackrect = {0, 0, _screenWidth * _scaleFactor, _newShakePos * _scaleFactor}; + SDL_Rect blackrect = {0, 0, _videoMode.screenWidth * _videoMode.scaleFactor, _newShakePos * _videoMode.scaleFactor}; - if (_adjustAspectRatio && !_overlayVisible) + if (_videoMode.aspectRatio && !_overlayVisible) blackrect.h = real2Aspect(blackrect.h - 1) + 1; SDL_FillRect(_hwscreen, &blackrect, 0); @@ -586,15 +622,15 @@ void OSystem_SDL::internUpdateScreen() { if (!_overlayVisible) { origSurf = _screen; srcSurf = _tmpscreen; - width = _screenWidth; - height = _screenHeight; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; scalerProc = _scalerProc; - scale1 = _scaleFactor; + scale1 = _videoMode.scaleFactor; } else { origSurf = _overlayscreen; srcSurf = _tmpscreen2; - width = _overlayWidth; - height = _overlayHeight; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; scalerProc = Normal1x; scale1 = 1; @@ -647,7 +683,7 @@ void OSystem_SDL::internUpdateScreen() { orig_dst_y = dst_y; dst_y = dst_y * scale1; - if (_adjustAspectRatio && !_overlayVisible) + if (_videoMode.aspectRatio && !_overlayVisible) dst_y = real2Aspect(dst_y); assert(scalerProc != NULL); @@ -661,7 +697,7 @@ void OSystem_SDL::internUpdateScreen() { r->h = dst_h * scale1; #ifndef DISABLE_SCALERS - if (_adjustAspectRatio && orig_dst_y < height && !_overlayVisible) + if (_videoMode.aspectRatio && orig_dst_y < height && !_overlayVisible) r->h = stretch200To240((uint8 *) _hwscreen->pixels, dstPitch, r->w, r->h, r->x, r->y, orig_dst_y * scale1); #endif } @@ -704,51 +740,24 @@ bool OSystem_SDL::saveScreenshot(const char *filename) { void OSystem_SDL::setFullscreenMode(bool enable) { Common::StackLock lock(_graphicsMutex); - if (_fullscreen == enable) + if (_oldVideoMode.setup && _oldVideoMode.fullscreen == enable) return; - if (_transactionMode == kTransactionCommit) { - assert(_hwscreen != 0); - _fullscreen = enable; - - // Switch between fullscreen and windowed mode by invoking hotswapGFXMode(). - // We used to use SDL_WM_ToggleFullScreen() in the past, but this caused various - // problems. E.g. on OS X, it was implemented incorrectly for a long time; on - // the MAEMO platform, it seems to have caused problems, too. - // And on Linux, there were some troubles, too (see bug #1705410). - // So, we just do it "manually" now. There shouldn't be any drawbacks to that - // anyway. - hotswapGFXMode(); - } else if (_transactionMode == kTransactionActive) { - _transactionDetails.fs = enable; - _transactionDetails.fsChanged = true; - + if (_transactionMode == kTransactionActive) { + _videoMode.fullscreen = enable; _transactionDetails.needHotswap = true; } } void OSystem_SDL::setAspectRatioCorrection(bool enable) { - if (((_screenHeight == 200 || _screenHeight == 400) && _adjustAspectRatio != enable) || - _transactionMode == kTransactionCommit) { - Common::StackLock lock(_graphicsMutex); - - //assert(_hwscreen != 0); - _adjustAspectRatio = enable; - - if (_transactionMode == kTransactionActive) { - _transactionDetails.ar = enable; - _transactionDetails.arChanged = true; - - _transactionDetails.needHotswap = true; + Common::StackLock lock(_graphicsMutex); - return; - } else { - if (_transactionMode != kTransactionCommit) - hotswapGFXMode(); - } + if (_oldVideoMode.setup && _oldVideoMode.aspectRatio == enable) + return; - // Make sure that an Common::EVENT_SCREEN_CHANGED gets sent later - _modeChanged = true; + if (_transactionMode == kTransactionActive) { + _videoMode.aspectRatio = enable; + _transactionDetails.needHotswap = true; } } @@ -763,13 +772,13 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int Common::StackLock lock(_graphicsMutex); // Lock the mutex until this function ends - assert(x >= 0 && x < _screenWidth); - assert(y >= 0 && y < _screenHeight); - assert(h > 0 && y + h <= _screenHeight); - assert(w > 0 && x + w <= _screenWidth); + assert(x >= 0 && x < _videoMode.screenWidth); + assert(y >= 0 && y < _videoMode.screenHeight); + assert(h > 0 && y + h <= _videoMode.screenHeight); + assert(w > 0 && x + w <= _videoMode.screenWidth); - if (((long)src & 3) == 0 && pitch == _screenWidth && x == 0 && y == 0 && - w == _screenWidth && h == _screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) { + if (((long)src & 3) == 0 && pitch == _videoMode.screenWidth && x == 0 && y == 0 && + w == _videoMode.screenWidth && h == _videoMode.screenHeight && _modeFlags & DF_WANT_RECT_OPTIM) { /* Special, optimized case for full screen updates. * It tries to determine what areas were actually changed, * and just updates those, on the actual display. */ @@ -788,12 +797,12 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int y = 0; } - if (w > _screenWidth - x) { - w = _screenWidth - x; + if (w > _videoMode.screenWidth - x) { + w = _videoMode.screenWidth - x; } - if (h > _screenHeight - y) { - h = _screenHeight - y; + if (h > _videoMode.screenHeight - y) { + h = _videoMode.screenHeight - y; } if (w <= 0 || h <= 0) @@ -807,15 +816,15 @@ void OSystem_SDL::copyRectToScreen(const byte *src, int pitch, int x, int y, int if (SDL_LockSurface(_screen) == -1) error("SDL_LockSurface failed: %s", SDL_GetError()); - byte *dst = (byte *)_screen->pixels + y * _screenWidth + x; + byte *dst = (byte *)_screen->pixels + y * _videoMode.screenWidth + x; - if (_screenWidth == pitch && pitch == w) { + if (_videoMode.screenWidth == pitch && pitch == w) { memcpy(dst, src, h*w); } else { do { memcpy(dst, src, w); src += pitch; - dst += _screenWidth; + dst += _videoMode.screenWidth; } while (--h); } @@ -875,11 +884,11 @@ void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) int height, width; if (!_overlayVisible && !realCoordinates) { - width = _screenWidth; - height = _screenHeight; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; } else { - width = _overlayWidth; - height = _overlayHeight; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; } // Extend the dirty region by 1 pixel for scalers @@ -911,7 +920,7 @@ void OSystem_SDL::addDirtyRect(int x, int y, int w, int h, bool realCoordinates) } #ifndef DISABLE_SCALERS - if (_adjustAspectRatio && !_overlayVisible && !realCoordinates) { + if (_videoMode.aspectRatio && !_overlayVisible && !realCoordinates) { makeRectStretchable(x, y, w, h); } #endif @@ -936,14 +945,14 @@ void OSystem_SDL::makeChecksums(const byte *buf) { assert(buf); uint32 *sums = _dirtyChecksums; uint x,y; - const uint last_x = (uint)_screenWidth / 8; - const uint last_y = (uint)_screenHeight / 8; + const uint last_x = (uint)_videoMode.screenWidth / 8; + const uint last_y = (uint)_videoMode.screenHeight / 8; const uint BASE = 65521; /* largest prime smaller than 65536 */ /* the 8x8 blocks in buf are enumerated starting in the top left corner and * reading each line at a time from left to right */ - for (y = 0; y != last_y; y++, buf += _screenWidth * (8 - 1)) + for (y = 0; y != last_y; y++, buf += _videoMode.screenWidth * (8 - 1)) for (x = 0; x != last_x; x++, buf += 8) { // Adler32 checksum algorithm (from RFC1950, used by gzip and zlib). // This computes the Adler32 checksum of a 8x8 pixel block. Note @@ -959,7 +968,7 @@ void OSystem_SDL::makeChecksums(const byte *buf) { s1 += ptr[subX]; s2 += s1; } - ptr += _screenWidth; + ptr += _videoMode.screenWidth; } s1 %= BASE; @@ -989,8 +998,8 @@ void OSystem_SDL::addDirtyRgnAuto(const byte *buf) { int x, y, w; uint32 *ck = _dirtyChecksums; - for (y = 0; y != _screenHeight / 8; y++) { - for (x = 0; x != _screenWidth / 8; x++, ck++) { + for (y = 0; y != _videoMode.screenHeight / 8; y++) { + for (x = 0; x != _videoMode.screenWidth / 8; x++, ck++) { if (ck[0] != ck[_cksumNum]) { /* found a dirty 8x8 block, now go as far to the right as possible, and at the same time, unmark the dirty status by setting old to new. */ @@ -998,7 +1007,7 @@ void OSystem_SDL::addDirtyRgnAuto(const byte *buf) { do { ck[w + _cksumNum] = ck[w]; w++; - } while (x + w != _screenWidth / 8 && ck[w] != ck[w + _cksumNum]); + } while (x + w != _videoMode.screenWidth / 8 && ck[w] != ck[w + _cksumNum]); addDirtyRect(x * 8, y * 8, w * 8, 8); @@ -1015,11 +1024,11 @@ void OSystem_SDL::addDirtyRgnAuto(const byte *buf) { } int16 OSystem_SDL::getHeight() { - return _screenHeight; + return _videoMode.screenHeight; } int16 OSystem_SDL::getWidth() { - return _screenWidth; + return _videoMode.screenWidth; } void OSystem_SDL::setPalette(const byte *colors, uint start, uint num) { @@ -1105,11 +1114,11 @@ void OSystem_SDL::showOverlay() { // Since resolution could change, put mouse to adjusted position // Fixes bug #1349059 - x = _mouseCurState.x * _scaleFactor; - if (_adjustAspectRatio) - y = real2Aspect(_mouseCurState.y) * _scaleFactor; + x = _mouseCurState.x * _videoMode.scaleFactor; + if (_videoMode.aspectRatio) + y = real2Aspect(_mouseCurState.y) * _videoMode.scaleFactor; else - y = _mouseCurState.y * _scaleFactor; + y = _mouseCurState.y * _videoMode.scaleFactor; warpMouse(x, y); @@ -1128,9 +1137,9 @@ void OSystem_SDL::hideOverlay() { // Since resolution could change, put mouse to adjusted position // Fixes bug #1349059 - x = _mouseCurState.x / _scaleFactor; - y = _mouseCurState.y / _scaleFactor; - if (_adjustAspectRatio) + x = _mouseCurState.x / _videoMode.scaleFactor; + y = _mouseCurState.y / _videoMode.scaleFactor; + if (_videoMode.aspectRatio) y = aspect2Real(y); warpMouse(x, y); @@ -1152,20 +1161,20 @@ void OSystem_SDL::clearOverlay() { SDL_Rect src, dst; src.x = src.y = 0; dst.x = dst.y = 1; - src.w = dst.w = _screenWidth; - src.h = dst.h = _screenHeight; + src.w = dst.w = _videoMode.screenWidth; + src.h = dst.h = _videoMode.screenHeight; if (SDL_BlitSurface(_screen, &src, _tmpscreen, &dst) != 0) error("SDL_BlitSurface failed: %s", SDL_GetError()); SDL_LockSurface(_tmpscreen); SDL_LockSurface(_overlayscreen); _scalerProc((byte *)(_tmpscreen->pixels) + _tmpscreen->pitch + 2, _tmpscreen->pitch, - (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _screenWidth, _screenHeight); + (byte *)_overlayscreen->pixels, _overlayscreen->pitch, _videoMode.screenWidth, _videoMode.screenHeight); #ifndef DISABLE_SCALERS - if (_adjustAspectRatio) + if (_videoMode.aspectRatio) stretch200To240((uint8 *)_overlayscreen->pixels, _overlayscreen->pitch, - _overlayWidth, _screenHeight * _scaleFactor, 0, 0, 0); + _videoMode.overlayWidth, _videoMode.screenHeight * _videoMode.scaleFactor, 0, 0, 0); #endif SDL_UnlockSurface(_tmpscreen); SDL_UnlockSurface(_overlayscreen); @@ -1183,9 +1192,9 @@ void OSystem_SDL::grabOverlay(OverlayColor *buf, int pitch) { error("SDL_LockSurface failed: %s", SDL_GetError()); byte *src = (byte *)_overlayscreen->pixels; - int h = _overlayHeight; + int h = _videoMode.overlayHeight; do { - memcpy(buf, src, _overlayWidth * 2); + memcpy(buf, src, _videoMode.overlayWidth * 2); src += _overlayscreen->pitch; buf += pitch; } while (--h); @@ -1211,12 +1220,12 @@ void OSystem_SDL::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, i y = 0; } - if (w > _overlayWidth - x) { - w = _overlayWidth - x; + if (w > _videoMode.overlayWidth - x) { + w = _videoMode.overlayWidth - x; } - if (h > _overlayHeight - y) { - h = _overlayHeight - y; + if (h > _videoMode.overlayHeight - y) { + h = _videoMode.overlayHeight - y; } if (w <= 0 || h <= 0) @@ -1264,12 +1273,12 @@ void OSystem_SDL::setMousePos(int x, int y) { void OSystem_SDL::warpMouse(int x, int y) { int y1 = y; - if (_adjustAspectRatio && !_overlayVisible) + if (_videoMode.aspectRatio && !_overlayVisible) y1 = real2Aspect(y); if (_mouseCurState.x != x || _mouseCurState.y != y) { if (!_overlayVisible) - SDL_WarpMouse(x * _scaleFactor, y1 * _scaleFactor); + SDL_WarpMouse(x * _videoMode.scaleFactor, y1 * _videoMode.scaleFactor); else SDL_WarpMouse(x, y1); @@ -1372,7 +1381,7 @@ void OSystem_SDL::blitCursor() { int rW, rH; - if (_cursorTargetScale >= _scaleFactor) { + if (_cursorTargetScale >= _videoMode.scaleFactor) { // The cursor target scale is greater or equal to the scale at // which the rest of the screen is drawn. We do not downscale // the cursor image, we draw it at its original size. It will @@ -1385,22 +1394,22 @@ void OSystem_SDL::blitCursor() { // The virtual dimensions may be larger than the original. - _mouseCurState.vW = w * _cursorTargetScale / _scaleFactor; - _mouseCurState.vH = h * _cursorTargetScale / _scaleFactor; + _mouseCurState.vW = w * _cursorTargetScale / _videoMode.scaleFactor; + _mouseCurState.vH = h * _cursorTargetScale / _videoMode.scaleFactor; _mouseCurState.vHotX = _mouseCurState.hotX * _cursorTargetScale / - _scaleFactor; + _videoMode.scaleFactor; _mouseCurState.vHotY = _mouseCurState.hotY * _cursorTargetScale / - _scaleFactor; + _videoMode.scaleFactor; } else { // The cursor target scale is smaller than the scale at which // the rest of the screen is drawn. We scale up the cursor // image to make it appear correct. - rW = w * _scaleFactor / _cursorTargetScale; - rH = h * _scaleFactor / _cursorTargetScale; - _mouseCurState.rHotX = _mouseCurState.hotX * _scaleFactor / + rW = w * _videoMode.scaleFactor / _cursorTargetScale; + rH = h * _videoMode.scaleFactor / _cursorTargetScale; + _mouseCurState.rHotX = _mouseCurState.hotX * _videoMode.scaleFactor / _cursorTargetScale; - _mouseCurState.rHotY = _mouseCurState.hotY * _scaleFactor / + _mouseCurState.rHotY = _mouseCurState.hotY * _videoMode.scaleFactor / _cursorTargetScale; // The virtual dimensions will be the same as the original. @@ -1415,7 +1424,7 @@ void OSystem_SDL::blitCursor() { int rH1 = rH; // store original to pass to aspect-correction function later #endif - if (_adjustAspectRatio && _cursorTargetScale == 1) { + if (_videoMode.aspectRatio && _cursorTargetScale == 1) { rH = real2Aspect(rH - 1) + 1; _mouseCurState.rHotY = real2Aspect(_mouseCurState.rHotY); } @@ -1450,17 +1459,17 @@ void OSystem_SDL::blitCursor() { // the game. This only works well with the non-blurring scalers so we // actually only use the 1x, 1.5x, 2x and AdvMame scalers. - if (_cursorTargetScale == 1 && (_mode == GFX_DOUBLESIZE || _mode == GFX_TRIPLESIZE)) + if (_cursorTargetScale == 1 && (_videoMode.mode == GFX_DOUBLESIZE || _videoMode.mode == GFX_TRIPLESIZE)) scalerProc = _scalerProc; else - scalerProc = scalersMagn[_cursorTargetScale - 1][_scaleFactor - 1]; + scalerProc = scalersMagn[_cursorTargetScale - 1][_videoMode.scaleFactor - 1]; scalerProc((byte *)_mouseOrigSurface->pixels + _mouseOrigSurface->pitch + 2, _mouseOrigSurface->pitch, (byte *)_mouseSurface->pixels, _mouseSurface->pitch, _mouseCurState.w, _mouseCurState.h); #ifndef DISABLE_SCALERS - if (_adjustAspectRatio && _cursorTargetScale == 1) + if (_videoMode.aspectRatio && _cursorTargetScale == 1) cursorStretch200To240((uint8 *)_mouseSurface->pixels, _mouseSurface->pitch, rW, rH1, 0, 0, 0); #endif @@ -1503,7 +1512,7 @@ void OSystem_SDL::undrawMouse() { // When we switch bigger overlay off mouse jumps. Argh! // This is intended to prevent undrawing offscreen mouse - if (!_overlayVisible && (x >= _screenWidth || y >= _screenHeight)) { + if (!_overlayVisible && (x >= _videoMode.screenWidth || y >= _videoMode.screenHeight)) { return; } @@ -1526,17 +1535,17 @@ void OSystem_SDL::drawMouse() { dst.y = _mouseCurState.y; if (!_overlayVisible) { - scale = _scaleFactor; - width = _screenWidth; - height = _screenHeight; + scale = _videoMode.scaleFactor; + width = _videoMode.screenWidth; + height = _videoMode.screenHeight; dst.w = _mouseCurState.vW; dst.h = _mouseCurState.vH; hotX = _mouseCurState.vHotX; hotY = _mouseCurState.vHotY; } else { scale = 1; - width = _overlayWidth; - height = _overlayHeight; + width = _videoMode.overlayWidth; + height = _videoMode.overlayHeight; dst.w = _mouseCurState.rW; dst.h = _mouseCurState.rH; hotX = _mouseCurState.rHotX; @@ -1558,7 +1567,7 @@ void OSystem_SDL::drawMouse() { dst.y += _currentShakePos; } - if (_adjustAspectRatio && !_overlayVisible) + if (_videoMode.aspectRatio && !_overlayVisible) dst.y = real2Aspect(dst.y); dst.x = scale * dst.x - _mouseCurState.rHotX; @@ -1674,17 +1683,19 @@ void OSystem_SDL::displayMessageOnOSD(const char *msg) { void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { // Ctrl-Alt-a toggles aspect ratio correction if (key.keysym.sym == 'a') { - setFeatureState(kFeatureAspectRatioCorrection, !_adjustAspectRatio); + beginGFXTransaction(); + setFeatureState(kFeatureAspectRatioCorrection, !_videoMode.aspectRatio); + endGFXTransaction(); #ifdef USE_OSD char buffer[128]; - if (_adjustAspectRatio) + if (_videoMode.aspectRatio) sprintf(buffer, "Enabled aspect ratio correction\n%d x %d -> %d x %d", - _screenWidth, _screenHeight, + _videoMode.screenWidth, _videoMode.screenHeight, _hwscreen->w, _hwscreen->h ); else sprintf(buffer, "Disabled aspect ratio correction\n%d x %d -> %d x %d", - _screenWidth, _screenHeight, + _videoMode.screenWidth, _videoMode.screenHeight, _hwscreen->w, _hwscreen->h ); displayMessageOnOSD(buffer); @@ -1694,7 +1705,7 @@ void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { } int newMode = -1; - int factor = _scaleFactor - 1; + int factor = _videoMode.scaleFactor - 1; // Increase/decrease the scale factor if (key.keysym.sym == SDLK_EQUALS || key.keysym.sym == SDLK_PLUS || key.keysym.sym == SDLK_MINUS || @@ -1720,13 +1731,15 @@ void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { } if (newMode >= 0) { - setGraphicsMode(newMode); + beginGFXTransaction(); + setGraphicsMode(newMode); + endGFXTransaction(); #ifdef USE_OSD if (_osdSurface) { const char *newScalerName = 0; const GraphicsMode *g = getSupportedGraphicsModes(); while (g->name) { - if (g->id == _mode) { + if (g->id == _videoMode.mode) { newScalerName = g->description; break; } @@ -1736,7 +1749,7 @@ void OSystem_SDL::handleScalerHotkeys(const SDL_KeyboardEvent &key) { char buffer[128]; sprintf(buffer, "Active graphics filter: %s\n%d x %d -> %d x %d", newScalerName, - _screenWidth, _screenHeight, + _videoMode.screenWidth, _videoMode.screenHeight, _hwscreen->w, _hwscreen->h ); displayMessageOnOSD(buffer); diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 02c2efccdb..a16d0a65df 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -116,25 +116,28 @@ void OSystem_SDL::initBackend() { // Enable unicode support if possible SDL_EnableUNICODE(1); + _oldVideoMode.setup = false; + _videoMode.setup = false; + _cksumValid = false; #if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) && !defined(DISABLE_SCALERS) - _mode = GFX_DOUBLESIZE; - _scaleFactor = 2; + _videoMode.mode = GFX_DOUBLESIZE; + _videoMode.scaleFactor = 2; + _videoMode.aspectRatio = ConfMan.getBool("aspect_ratio"); _scalerProc = Normal2x; - _adjustAspectRatio = ConfMan.getBool("aspect_ratio"); #else // for small screen platforms - _mode = GFX_NORMAL; - _scaleFactor = 1; + _videoMode.mode = GFX_NORMAL; + _videoMode.scaleFactor = 1; + _videoMode.aspectRatio = false; _scalerProc = Normal1x; - _adjustAspectRatio = false; #endif _scalerType = 0; _modeFlags = 0; #if !defined(_WIN32_WCE) && !defined(__SYMBIAN32__) - _fullscreen = ConfMan.getBool("fullscreen"); + _videoMode.fullscreen = ConfMan.getBool("fullscreen"); #else - _fullscreen = true; + _videoMode.fullscreen = true; #endif #if !defined(MACOSX) && !defined(__SYMBIAN32__) @@ -192,8 +195,7 @@ OSystem_SDL::OSystem_SDL() #ifdef USE_OSD _osdSurface(0), _osdAlpha(SDL_ALPHA_TRANSPARENT), _osdFadeStartTime(0), #endif - _hwscreen(0), _screen(0), _screenWidth(0), _screenHeight(0), - _tmpscreen(0), _overlayWidth(0), _overlayHeight(0), + _hwscreen(0), _screen(0), _tmpscreen(0), _overlayVisible(false), _overlayscreen(0), _tmpscreen2(0), _samplesPerSec(0), @@ -429,9 +431,9 @@ bool OSystem_SDL::getFeatureState(Feature f) { switch (f) { case kFeatureFullscreenMode: - return _fullscreen; + return _videoMode.fullscreen; case kFeatureAspectRatioCorrection: - return _adjustAspectRatio; + return _videoMode.aspectRatio; case kFeatureAutoComputeDirtyRects: return _modeFlags & DF_WANT_RECT_OPTIM; default: diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h index 6005b14e1c..207ed50d63 100644 --- a/backends/platform/sdl/sdl.h +++ b/backends/platform/sdl/sdl.h @@ -80,7 +80,7 @@ public: virtual void initBackend(); void beginGFXTransaction(void); - void endGFXTransaction(void); + TransactionError endGFXTransaction(void); // Set the size of the video bitmap. // Typically, 320x200 @@ -179,8 +179,8 @@ public: virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); virtual int16 getHeight(); virtual int16 getWidth(); - virtual int16 getOverlayHeight() { return _overlayHeight; } - virtual int16 getOverlayWidth() { return _overlayWidth; } + virtual int16 getOverlayHeight() { return _videoMode.overlayHeight; } + virtual int16 getOverlayWidth() { return _videoMode.overlayWidth; } virtual const GraphicsMode *getSupportedGraphicsModes() const; virtual int getDefaultGraphicsMode() const; @@ -226,16 +226,12 @@ protected: // unseen game screen SDL_Surface *_screen; - // TODO: We could get rid of the following two vars and just use _screen instead - int _screenWidth, _screenHeight; - // temporary screen (for scalers) SDL_Surface *_tmpscreen; SDL_Surface *_tmpscreen2; // overlay SDL_Surface *_overlayscreen; - int _overlayWidth, _overlayHeight; bool _overlayVisible; Graphics::PixelFormat _overlayFormat; @@ -253,36 +249,39 @@ protected: enum { kTransactionNone = 0, - kTransactionCommit = 1, - kTransactionActive = 2 + kTransactionActive = 1, + kTransactionRollback = 2 }; struct TransactionDetails { - int mode; - bool modeChanged; - int w; - int h; bool sizeChanged; - bool fs; - bool fsChanged; - bool ar; - bool arChanged; bool needHotswap; bool needUpdatescreen; - bool needUnload; - bool needToggle; bool normal1xScaler; }; TransactionDetails _transactionDetails; + struct VideoState { + bool setup; + + bool fullscreen; + bool aspectRatio; + + int mode; + int scaleFactor; + + int screenWidth, screenHeight; + int overlayWidth, overlayHeight; + }; + VideoState _videoMode, _oldVideoMode; + + void setGraphicsModeIntern(); + /** Force full redraw on next updateScreen */ bool _forceFull; ScalerProc *_scalerProc; int _scalerType; - int _scaleFactor; - int _mode; int _transactionMode; - bool _fullscreen; bool _screenIsLocked; Graphics::Surface _framebuffer; @@ -292,9 +291,6 @@ protected: bool _modeChanged; int _screenChangeCount; - /** True if aspect ratio correction is enabled. */ - bool _adjustAspectRatio; - enum { NUM_DIRTY_RECT = 100, MAX_SCALING = 3 @@ -417,9 +413,9 @@ protected: virtual void internUpdateScreen(); // overloaded by CE backend - virtual void loadGFXMode(); // overloaded by CE backend + virtual bool loadGFXMode(); // overloaded by CE backend virtual void unloadGFXMode(); // overloaded by CE backend - virtual void hotswapGFXMode(); // overloaded by CE backend + virtual bool hotswapGFXMode(); // overloaded by CE backend void setFullscreenMode(bool enable); void setAspectRatioCorrection(bool enable); @@ -427,8 +423,8 @@ protected: virtual bool saveScreenshot(const char *filename); // overloaded by CE backend int effectiveScreenHeight() const { - return (_adjustAspectRatio ? real2Aspect(_screenHeight) : _screenHeight) - * _scaleFactor; + return (_videoMode.aspectRatio ? real2Aspect(_videoMode.screenHeight) : _videoMode.screenHeight) + * _videoMode.scaleFactor; } void setupIcon(); -- cgit v1.2.3