diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index 37e1fabdc76..a92a721cce1 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -120,7 +120,7 @@ SurfaceSdlGraphicsManager::SurfaceSdlGraphicsManager(SdlEventSource *sdlEventSou #if defined(WIN32) && !SDL_VERSION_ATLEAST(2, 0, 0) _originalBitsPerPixel(0), #endif - _screen(0), _tmpscreen(0), _oldscreen(0), _destbuffer(0), + _screen(0), _tmpscreen(0), _destbuffer(0), _screenFormat(Graphics::PixelFormat::createFormatCLUT8()), _cursorFormat(Graphics::PixelFormat::createFormatCLUT8()), _useOldSrc(false), @@ -682,17 +682,8 @@ void SurfaceSdlGraphicsManager::setGraphicsModeIntern() { _extraPixels = (*_scalerPlugin)->extraPixels(); _useOldSrc = (*_scalerPlugin)->useOldSrc(); if (_useOldSrc) { - if (!_oldscreen) { - _oldscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + _maxExtraPixels * 2, - _videoMode.screenHeight + _maxExtraPixels * 2, - 16, - _hwscreen->format->Rmask, - _hwscreen->format->Gmask, - _hwscreen->format->Bmask, - _hwscreen->format->Amask); - if (_oldscreen == NULL) - error("allocating _oldscreen failed"); - } + (*_scalerPlugin)->setSource((byte *)_tmpscreen->pixels, _tmpscreen->pitch, + _videoMode.screenWidth, _videoMode.screenHeight, _maxExtraPixels, SRC_SCREEN); if (!_destbuffer) { _destbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth * _videoMode.scaleFactor, _videoMode.screenHeight * _videoMode.scaleFactor, @@ -989,15 +980,8 @@ bool SurfaceSdlGraphicsManager::loadGFXMode() { if (_useOldSrc) { // Create surface containing previous frame's data to pass to scaler - _oldscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth + _maxExtraPixels * 2, - _videoMode.screenHeight + _maxExtraPixels * 2, - 16, - _hwscreen->format->Rmask, - _hwscreen->format->Gmask, - _hwscreen->format->Bmask, - _hwscreen->format->Amask); - if (_oldscreen == NULL) - error("allocating _oldscreen failed"); + (*_scalerPlugin)->setSource((byte *)_tmpscreen->pixels, _tmpscreen->pitch, + _videoMode.screenWidth, _videoMode.screenHeight, _maxExtraPixels, SRC_SCREEN); // Create surface containing the raw output from the scaler _destbuffer = SDL_CreateRGBSurface(SDL_SWSURFACE, _videoMode.screenWidth * _videoMode.scaleFactor, @@ -1057,11 +1041,6 @@ void SurfaceSdlGraphicsManager::unloadGFXMode() { _tmpscreen = NULL; } - if (_oldscreen) { - SDL_FreeSurface(_oldscreen); - _oldscreen = NULL; - } - if (_destbuffer) { SDL_FreeSurface(_destbuffer); _destbuffer = NULL; @@ -1110,6 +1089,7 @@ bool SurfaceSdlGraphicsManager::hotswapGFXMode() { _overlayscreen = NULL; // Release the HW screen surface +<<<<<<< HEAD if (_hwScreen) { SDL_FreeSurface(_hwScreen); _hwScreen = NULL; @@ -1118,10 +1098,6 @@ bool SurfaceSdlGraphicsManager::hotswapGFXMode() { SDL_FreeSurface(_tmpscreen); _tmpscreen = NULL; } - if (_oldscreen) { - SDL_FreeSurface(_oldscreen); - _oldscreen = NULL; - } if (_destbuffer) { SDL_FreeSurface(_destbuffer); _destbuffer = NULL; @@ -1277,7 +1253,6 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { SDL_LockSurface(srcSurf); SDL_LockSurface(_hwScreen); if (_useOldSrc && !_overlayVisible) { - SDL_LockSurface(_oldscreen); SDL_LockSurface(_destbuffer); } @@ -1322,10 +1297,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { } else { if (_useOldSrc) { // scale into _destbuffer instead of _hwscreen to avoid AR problems - (*_scalerPlugin)->oldSrcScale((byte *)srcSurf->pixels + (r->x + _maxExtraPixels) * 2 + (r->y + _maxExtraPixels) * srcPitch, srcPitch, - (byte *)_destbuffer->pixels + rx1 * 2 + orig_dst_y * scale1 * _destbuffer->pitch, _destbuffer->pitch, - (byte *)_oldscreen->pixels + (r->x + _maxExtraPixels) * 2 + (r->y + _maxExtraPixels) * _oldscreen->pitch, _oldscreen->pitch, - r->w, dst_h, r->x, r->y); + (*_scalerPlugin)->oldSrcScale((byte *)_destbuffer->pixels, _destbuffer->pitch, SRC_SCREEN); } else (*_scalerPlugin)->scale((byte *)srcSurf->pixels + (r->x + _maxExtraPixels) * 2 + (r->y + _maxExtraPixels) * srcPitch, srcPitch, (byte *)_hwscreen->pixels + rx1 * 2 + dst_y * dstPitch, dstPitch, r->w, dst_h, r->x, r->y); @@ -1363,14 +1335,7 @@ void SurfaceSdlGraphicsManager::internUpdateScreen() { SDL_UnlockSurface(_hwScreen); if (_useOldSrc && !_overlayVisible) { - SDL_UnlockSurface(_oldscreen); SDL_UnlockSurface(_destbuffer); - - // Swap old and new screen - SDL_Surface *tmp; - tmp = _oldscreen; - _oldscreen = _tmpscreen; - _tmpscreen = tmp; } // Readjust the dirty rect list in case we are doing a full update. diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index d81f64fa06c..9a4ff45a8f2 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -216,8 +216,6 @@ protected: /** Temporary screen (for scalers) */ SDL_Surface *_tmpscreen; - /** Previous frame's screen (for scalers) */ - SDL_Surface *_oldscreen; /** Previous frame's raw scaled screen (for scalers) */ SDL_Surface *_destbuffer; /** Temporary screen (for scalers) */ diff --git a/graphics/module.mk b/graphics/module.mk index 341c0e0d6f5..a6f9008d94c 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -31,6 +31,7 @@ MODULE_OBJS := \ primitives.o \ renderer.o \ scaler.o \ + scalerplugin.o \ scaler/thumbnail_intern.o \ screen.o \ scaler/normal.o \ diff --git a/graphics/scaler/edge.cpp b/graphics/scaler/edge.cpp index 6080c9fc5d0..1a63ebaceb0 100644 --- a/graphics/scaler/edge.cpp +++ b/graphics/scaler/edge.cpp @@ -3561,8 +3561,8 @@ void EdgePlugin::scale(const uint8 *srcPtr, uint32 srcPitch, } } -void EdgePlugin::oldSrcScale(const uint8 *srcPtr, uint32 srcPitch, - uint8 *dstPtr, uint32 dstPitch, const uint8 *oldSrcPtr, uint32 oldSrcPitch, int width, int height, int x, int y) { +void EdgePlugin::internScale(const uint8 *srcPtr, uint32 srcPitch, + uint8 *dstPtr, uint32 dstPitch, const uint8 *oldSrcPtr, uint32 oldSrcPitch, int width, int height) { if (_format.bytesPerPixel == 2) { if (_factor == 2) { if (_format.gLoss == 2) diff --git a/graphics/scaler/edge.h b/graphics/scaler/edge.h index dcf779c1b5b..2c8ff5af013 100644 --- a/graphics/scaler/edge.h +++ b/graphics/scaler/edge.h @@ -24,7 +24,7 @@ #include "graphics/scalerplugin.h" -class EdgePlugin : public ScalerPluginObject { +class EdgePlugin : public SourceScaler { public: EdgePlugin(); @@ -32,10 +32,10 @@ public: virtual void deinitialize(); virtual void scale(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, int width, int height, int x, int y); - virtual void oldSrcScale(const uint8 *srcPtr, uint32 srcPitch, + virtual void internScale(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 dstPitch, const uint8 *oldSrcPtr, uint32 oldSrcPitch, - int width, int height, int x, int y); + int width, int height); virtual uint increaseFactor(); virtual uint decreaseFactor(); virtual uint getFactor() const { return _factor; } diff --git a/graphics/scalerplugin.cpp b/graphics/scalerplugin.cpp new file mode 100644 index 00000000000..1496b81345c --- /dev/null +++ b/graphics/scalerplugin.cpp @@ -0,0 +1,54 @@ +/* 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "graphics/scalerplugin.h" + +SourceScaler::SourceScaler() { + for (int i = 0; i < SRC_MAX; ++i) { + oldSrcs[i] = NULL; + } +} + +void SourceScaler::setSource(byte *src, uint pitch, int width, int height, int padding, SourceType type) { + widths[type] = width; + heights[type] = height; + pitches[type] = pitch; + newSrcs[type] = src; + paddings[type] = padding; + + if (oldSrcs[type] != NULL) + free(oldSrcs[type]); + + int size = (height + _format.bytesPerPixel * padding) * 2 * pitch; + oldSrcs[type] = new byte[size]; + memset(oldSrcs[type], 0, size); +} + +void SourceScaler::oldSrcScale(byte *dst, uint dstPitch, SourceType type) { + // Call user defined scale function + internScale(newSrcs[type] + paddings[type] * 2 + pitches[type] * paddings[type], pitches[type], + dst, dstPitch, + oldSrcs[type] + paddings[type] * 2 + pitches[type] * paddings[type], pitches[type], + widths[type], heights[type]); + // Update old src + memcpy(oldSrcs[type], newSrcs[type], (heights[type] + _format.bytesPerPixel * paddings[type]) * 2 * pitches[type]); +} + diff --git a/graphics/scalerplugin.h b/graphics/scalerplugin.h index 9c103c16445..6a0451fb3ce 100644 --- a/graphics/scalerplugin.h +++ b/graphics/scalerplugin.h @@ -25,6 +25,15 @@ #include "base/plugins.h" #include "graphics/pixelformat.h" +enum SourceType { + SRC_SCREEN = 0, + SRC_CURSOR, + SRC_OTHER, + + SRC_MAX +}; + + class ScalerPluginObject : public PluginObject { public: @@ -96,18 +105,29 @@ public: * optionally call it. * * @see oldSourceScale + * @see setSource */ virtual bool useOldSrc() const { return false; } /** - * Secondary scaling method for computationally intense scalers. + * Set the source to be used when scaling and copying to the old buffer. * - * @see useOldSource + * @param padding The number of pixels on the border (Used to prevent memory access crashes) + * @param type The surface type. This source will only be used when calling oldSrcScale with the same type. */ - virtual void oldSrcScale(const uint8 *srcPtr, uint32 srcPitch, - uint8 *dstPtr, uint32 dstPitch, - const uint8 *oldSrcPtr, uint32 oldSrcPitch, - int width, int height, int x, int y) { + virtual void setSource(byte *src, uint pitch, int width, int height, int padding, SourceType type) { + // Should not be called unless overriden + assert(0); + } + + /** + * Scale using the source from setSource called with the same value as type. + * The source will be compared against previous frames to avoid computations + * on unchanged pixels. + * + * @param type The surface type set previously with setSource + */ + virtual void oldSrcScale(byte *dst, uint dstPitch, SourceType type) { // Should not be called unless overriden assert(0); } @@ -118,6 +138,40 @@ protected: Graphics::PixelFormat _format; }; +/** + * Convenience class that implements some bookkeeping for keeping track of + * old source images. + */ +class SourceScaler : public ScalerPluginObject { + +public: + + SourceScaler(); + + virtual void setSource(byte *src, uint pitch, int width, int height, int padding, SourceType type); + virtual void oldSrcScale(byte *dst, uint dstPitch, SourceType type); + +protected: + + /** + * Scalers must implement this function. It will be called by oldSrcScale. + * If by comparing the src and oldsrc images it is discovered that no change + * is necessary, do not write a pixel. + */ + virtual void internScale(const uint8 *srcPtr, uint32 srcPitch, + uint8 *dstPtr, uint32 dstPitch, + const uint8 *oldSrcPtr, uint32 oldSrcPitch, + int width, int height) = 0; + + int widths[SRC_MAX]; + int heights[SRC_MAX]; + uint paddings[SRC_MAX]; + uint pitches[SRC_MAX]; + + byte *newSrcs[SRC_MAX]; + byte *oldSrcs[SRC_MAX]; +}; + typedef PluginSubclass ScalerPlugin; /**