/* * The ManaPlus Client * Copyright (C) 2013-2014 The ManaPlus Developers * * This file is part of The ManaPlus Client. * * 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 * 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 "utils/sdlcheckutils.h" #ifdef DEBUG_SDL_SURFACES #include "logger.h" #include "utils/stringutils.h" #include <map> #include <SDL_image.h> #include <SDL_ttf.h> #include "debug.h" #define DEBUG_SURFACE_ALLOCATION 1 struct MemoryObject { MemoryObject(const std::string &name, const char *const file, const unsigned int line) : mName(name), mAddFile(strprintf("%s:%u", file, line)), mRemoveFile(), mCnt(1) { } std::string mName; std::string mAddFile; std::string mRemoveFile; int mCnt; }; std::map<void*, MemoryObject*> mSurfaces; static SDL_Surface *addSurface(const char *restrict const name, SDL_Surface *restrict const surface, const char *restrict const file, const unsigned line) { #ifdef DEBUG_SURFACE_ALLOCATION logger->log("add surface: %s %s:%u %p", name, file, line, static_cast<void*>(surface)); #endif std::map<void*, MemoryObject*>::iterator it = mSurfaces.find(surface); if (it != mSurfaces.end()) { MemoryObject *const obj = (*it).second; if (obj) { // found some time ago created surface #ifdef DEBUG_SURFACE_ALLOCATION logger->log("adding existing surface: %p, count:%d\n" "was add %s\nwas deleted %s", surface, obj->mCnt, obj->mAddFile.c_str(), obj->mRemoveFile.c_str()); #endif obj->mCnt ++; } } else { // creating surface object mSurfaces[surface] = new MemoryObject(name, file, line); } return surface; } static void deleteSurface(const char *restrict const name A_UNUSED, SDL_Surface *restrict const surface, const char *restrict const file, const unsigned line) { #ifdef DEBUG_SURFACE_ALLOCATION logger->log("delete surface: %s %s:%u %p", name, file, line, surface); #endif std::map<void*, MemoryObject*>::iterator it = mSurfaces.find(surface); if (it == mSurfaces.end()) { logger->log("bad surface delete: %p at %s:%d", static_cast<void*>(surface), file, line); } else { MemoryObject *const obj = (*it).second; if (obj) { const int cnt = obj->mCnt; #ifdef DEBUG_SURFACE_ALLOCATION logger->log("debug deleting surface: %p, count:%d\n" "was add %s\nwas deleted %s", surface, cnt, obj->mAddFile.c_str(), obj->mRemoveFile.c_str()); #endif if (cnt < 1) { // surface was here but was deleted logger->log("deleting already deleted surface: %p at %s:%d\n" "was add %s\nwas deleted %s", static_cast<void*>(surface), file, line, obj->mAddFile.c_str(), obj->mRemoveFile.c_str()); } else if (cnt == 1) { mSurfaces.erase(surface); delete obj; } else { obj->mCnt --; obj->mRemoveFile = strprintf("%s:%u", file, line); } } } } SDL_Surface *FakeIMG_LoadPNG_RW(SDL_RWops *const src, const char *const file, const unsigned line) { return addSurface("IMG_LoadPNG_RW", IMG_LoadPNG_RW(src), file, line); } SDL_Surface *FakeIMG_LoadJPG_RW(SDL_RWops *const src, const char *const file, const unsigned line) { return addSurface("IMG_LoadJPG_RW", IMG_LoadJPG_RW(src), file, line); } SDL_Surface *FakeIMG_Load(const char *name, const char *const file, const unsigned line) { return addSurface("IMG_Load", IMG_Load(name), file, line); } void FakeSDL_FreeSurface(SDL_Surface *const surface, const char *const file, const unsigned line) { deleteSurface("SDL_FreeSurface", surface, file, line); SDL_FreeSurface(surface); } SDL_Surface *FakeSDL_CreateRGBSurface(const uint32_t flags, const int width, const int height, const int depth, const uint32_t rMask, const uint32_t gMask, const uint32_t bMask, const uint32_t aMask, const char *const file, const unsigned line) { return addSurface("SDL_CreateRGBSurface", SDL_CreateRGBSurface(flags, width, height, depth, rMask, gMask, bMask, aMask), file, line); } SDL_Surface *FakeSDL_ConvertSurface(SDL_Surface *const src, SDL_PixelFormat *const fmt, const uint32_t flags, const char *const file, const unsigned line) { return addSurface("SDL_ConvertSurface", SDL_ConvertSurface( src, fmt, flags), file, line); } SDL_Surface *FakeTTF_RenderUTF8_Blended(_TTF_Font *const font, const char *restrict const text, const SDL_Color &fg, const char *restrict const file, const unsigned line) { return addSurface("TTF_RenderUTF8_Blended", TTF_RenderUTF8_Blended( font, text, fg), file, line); } SDL_Surface *FakeSDL_DisplayFormat(SDL_Surface *const surface, const char *const file, const unsigned line) { return addSurface("SDL_DisplayFormat", SDL_DisplayFormat(surface), file, line); } SDL_Surface *FakeSDL_DisplayFormatAlpha(SDL_Surface *const surface, const char *const file, const unsigned line) { return addSurface("SDL_DisplayFormatAlpha", SDL_DisplayFormatAlpha(surface), file, line); } #endif // DEBUG_SDL_SURFACES