rendered paste bodyFrom 3b04d0defc80c1a5aedddfd93d8d79493d7ec65e Mon Sep 17 00:00:00 2001From: Andrei Karas <akaras@inbox.ru>Date: Tue, 12 Oct 2010 19:59:25 +0300Subject: [PATCH] Impliment opacity cache for SDL surfaces.Enabled by default.Can be disabled in configuration option "alphaCache" if set it to 0.--- src/client.cpp | 2 + src/gui/gui.cpp | 3 + src/resources/image.cpp | 90 ++++++++++++++++++++++++++++++++++--- src/resources/image.h | 25 +++++++++- src/resources/resourcemanager.cpp | 15 ++++++ src/resources/resourcemanager.h | 6 +++ 6 files changed, 131 insertions(+), 10 deletions(-)diff --git a/src/client.cpp b/src/client.cppindex f1b363e..e4203af 100644--- a/src/client.cpp+++ b/src/client.cpp@@ -251,6 +251,8 @@ Client::Client(const Options &options): "Exiting.", mLocalDataDir.c_str())); } + Image::setEnableAlphaCache(config.getValue("alphaCache", true));+ #if defined __APPLE__ CFBundleRef mainBundle = CFBundleGetMainBundle(); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(mainBundle);diff --git a/src/gui/gui.cpp b/src/gui/gui.cppindex df2ddad..75f6743 100644--- a/src/gui/gui.cpp+++ b/src/gui/gui.cpp@@ -160,6 +160,9 @@ Gui::~Gui() void Gui::logic() {+ ResourceManager *resman = ResourceManager::getInstance();+ resman->clearScheduled();+ // Fade out mouse cursor after extended inactivity if (mMouseInactivityTimer < 100 * 15) {diff --git a/src/resources/image.cpp b/src/resources/image.cppindex 82799bc..9996330 100644--- a/src/resources/image.cpp+++ b/src/resources/image.cpp@@ -22,6 +22,7 @@ #include "resources/image.h" #include "resources/dye.h"+#include "resources/resourcemanager.h" #ifdef USE_OPENGL #include "openglgraphics.h"@@ -37,6 +38,7 @@ bool Image::mUseOpenGL = false; int Image::mTextureType = 0; int Image::mTextureSize = 0; #endif+bool Image::mEnableAlphaCache = false; Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): mAlpha(1.0f),@@ -48,6 +50,8 @@ Image::Image(SDL_Surface *image, bool hasAlphaChannel, Uint8 *alphaChannel): mGLImage = 0; #endif + mUseAlphaCache = Image::mEnableAlphaCache;+ mBounds.x = 0; mBounds.y = 0; @@ -71,6 +75,7 @@ Image::Image(GLuint glimage, int width, int height, int texWidth, int texHeight) mHasAlphaChannel(true), mSDLSurface(0), mAlphaChannel(0),+ mUseAlphaCache(false), mGLImage(glimage), mTexWidth(texWidth), mTexHeight(texHeight)@@ -166,12 +171,28 @@ Image *Image::load(SDL_Surface *tmpImage) return _SDLload(tmpImage); } +void Image::cleanCache()+{+ ResourceManager *resman = ResourceManager::getInstance();++ for (std::map<float, SDL_Surface*>::iterator+ i = mAlphaCache.begin(), i_end = mAlphaCache.end();+ i != i_end; ++i)+ {+ if (mSDLSurface != i->second)+ resman->scheduleDelete(i->second);+ i->second = 0;+ }+ mAlphaCache.clear();+}+ void Image::unload() { mLoaded = false; if (mSDLSurface) {+ cleanCache(); // Free the image surface. SDL_FreeSurface(mSDLSurface); mSDLSurface = NULL;@@ -211,6 +232,14 @@ bool Image::hasAlphaChannel() return false; } +SDL_Surface *Image::getByAlpha(float alpha)+{+ std::map<float, SDL_Surface*>::iterator it = mAlphaCache.find(alpha);+ if (it != mAlphaCache.end())+ return (*it).second;+ return 0;+}+ void Image::setAlpha(float alpha) { if (mAlpha == alpha)@@ -219,10 +248,34 @@ void Image::setAlpha(float alpha) if (alpha < 0.0f || alpha > 1.0f) return; - mAlpha = alpha;- if (mSDLSurface) {+ if (mUseAlphaCache)+ {+ SDL_Surface *surface = getByAlpha(mAlpha);+ if (!surface)+ {+ if (mAlphaCache.size() > 100)+ cleanCache();++ mAlphaCache[mAlpha] = mSDLSurface;+ }+ surface = getByAlpha(alpha);+ if (surface)+ {+ mAlphaCache.erase(alpha);+ mSDLSurface = surface;+ mAlpha = alpha;+ return;+ }+ else+ {+ mSDLSurface = Image::duplicateSurface(mSDLSurface);+ }+ }++ mAlpha = alpha;+ if (!hasAlphaChannel()) { // Set the alpha value this image is drawn at@@ -371,6 +424,14 @@ Image* Image::SDLgetScaledImage(int width, int height) return scaledImage; } +SDL_Surface* Image::duplicateSurface(SDL_Surface* tmpImage)+{+ if (!tmpImage || !tmpImage->format)+ return NULL;++ return SDL_ConvertSurface(tmpImage, tmpImage->format, SDL_SWSURFACE);+}+ Image *Image::_SDLload(SDL_Surface *tmpImage) { if (!tmpImage)@@ -560,25 +621,40 @@ Image *Image::getSubImage(int x, int y, int width, int height) return new SubImage(this, mSDLSurface, x, y, width, height); } +void Image::terminateAlphaCache()+{+ cleanCache();+ mUseAlphaCache = false;+}+ //============================================================================ // SubImage Class //============================================================================ SubImage::SubImage(Image *parent, SDL_Surface *image,- int x, int y, int width, int height):+ int x, int y, int width, int height): Image(image), mParent(parent) {- mParent->incRef();-- mHasAlphaChannel = mParent->hasAlphaChannel();- mAlphaChannel = mParent->SDLgetAlphaChannel();+ if (mParent)+ {+ mParent->incRef();+ mParent->terminateAlphaCache();+ mHasAlphaChannel = mParent->hasAlphaChannel();+ mAlphaChannel = mParent->SDLgetAlphaChannel();+ }+ else+ {+ mHasAlphaChannel = false;+ mAlphaChannel = 0;+ } // Set up the rectangle. mBounds.x = x; mBounds.y = y; mBounds.w = width; mBounds.h = height;+ mUseAlphaCache = false; } #ifdef USE_OPENGLdiff --git a/src/resources/image.h b/src/resources/image.hindex 3e8ad55..815b776 100644--- a/src/resources/image.h+++ b/src/resources/image.h@@ -39,6 +39,8 @@ #include <SDL_opengl.h> #endif +#include <map>+ class Dye; class Position; @@ -169,6 +171,15 @@ class Image : public Resource Uint8 *SDLgetAlphaChannel() const { return mAlphaChannel; } + SDL_Surface* duplicateSurface(SDL_Surface* tmpImage);++ void cleanCache();++ void terminateAlphaCache();++ static void setEnableAlphaCache(bool n)+ { mEnableAlphaCache = n; }+ #ifdef USE_OPENGL // OpenGL only public functions@@ -208,14 +219,22 @@ class Image : public Resource /** SDL_Surface to SDL_Surface Image loader */ static Image *_SDLload(SDL_Surface *tmpImage); + SDL_Surface *getByAlpha(float alpha);+ SDL_Surface *mSDLSurface; /** Alpha Channel pointer used for 32bit based SDL surfaces */ Uint8 *mAlphaChannel; - // ------------------------ // OpenGL protected members- // -----------------------+ std::map<float, SDL_Surface*> mAlphaCache;++ bool mUseAlphaCache;++ static bool mEnableAlphaCache;++ // -----------------------+ // OpenGL protected members+ // ----------------------- #ifdef USE_OPENGL /** * OpenGL Constructor.diff --git a/src/resources/resourcemanager.cpp b/src/resources/resourcemanager.cppindex c63b626..00e4726 100644--- a/src/resources/resourcemanager.cpp+++ b/src/resources/resourcemanager.cpp@@ -533,3 +533,18 @@ SDL_Surface *ResourceManager::loadSDLSurface(const std::string &filename) return tmp; }++void ResourceManager::scheduleDelete(SDL_Surface* surface)+{+ mDeletedSurfaces.insert(surface);+}++void ResourceManager::clearScheduled()+{+ for (std::set<SDL_Surface*>::iterator i = mDeletedSurfaces.begin(),+ i_end = mDeletedSurfaces.end(); i != i_end; ++i)+ {+ SDL_FreeSurface(*i);+ }+ mDeletedSurfaces.clear();+}diff --git a/src/resources/resourcemanager.h b/src/resources/resourcemanager.hindex 28ab472..870182e 100644--- a/src/resources/resourcemanager.h+++ b/src/resources/resourcemanager.h@@ -26,6 +26,7 @@ #include <map> #include <string> #include <vector>+#include <set> class Image; class ImageSet;@@ -205,6 +206,10 @@ class ResourceManager */ SDL_Surface *loadSDLSurface(const std::string &filename); + void scheduleDelete(SDL_Surface* surface);++ void clearScheduled();+ /** * Returns an instance of the class, creating one if it does not * already exist.@@ -227,6 +232,7 @@ class ResourceManager static ResourceManager *instance; typedef std::map<std::string, Resource*> Resources; typedef Resources::iterator ResourceIterator;+ std::set<SDL_Surface*> mDeletedSurfaces; Resources mResources; Resources mOrphanedResources; time_t mOldestOrphan;-- 1.7.2.3