Fix memory leaks

* Fix recursive reference memory leak in UIWidget
* Make Event/ScheduledEvent memory-leak safe
* Fix exit crashs by freeing graphics resources before destroying GL context
* Add many asserts to avoid any leak regression
This commit is contained in:
Eduardo Bart
2012-06-18 05:13:52 -03:00
parent f650b0e5bb
commit 1c7bbaea89
42 changed files with 326 additions and 81 deletions

View File

@@ -27,11 +27,13 @@
#include "glutil.h"
class Texture;
class TextureManager;
class Image;
class AnimatedTexture;
class BitmapFont;
class CachedText;
class FrameBuffer;
class FrameBufferManager;
class Shader;
class ShaderProgram;
class PainterShaderProgram;

View File

@@ -32,10 +32,10 @@ FontManager::FontManager()
m_defaultFont = BitmapFontPtr(new BitmapFont("emptyfont"));
}
void FontManager::releaseFonts()
void FontManager::terminate()
{
m_defaultFont.reset();
m_fonts.clear();
m_defaultFont = nullptr;
}
bool FontManager::importFont(std::string fontFile)

View File

@@ -30,10 +30,8 @@ class FontManager
public:
FontManager();
/// Release fonts references, thus making possible to destruct them
void releaseFonts();
void terminate();
/// Import a font from .otfont file
bool importFont(std::string fontFile);
bool fontExists(const std::string& fontName);

View File

@@ -23,7 +23,9 @@
#include "framebuffer.h"
#include "graphics.h"
#include "texture.h"
#include <framework/platform/platformwindow.h>
#include <framework/application.h>
uint FrameBuffer::boundFbo = 0;
@@ -32,12 +34,6 @@ FrameBuffer::FrameBuffer()
internalCreate();
}
FrameBuffer::FrameBuffer(const Size& size)
{
internalCreate();
resize(size);
}
void FrameBuffer::internalCreate()
{
m_prevBoundFbo = 0;
@@ -51,14 +47,14 @@ void FrameBuffer::internalCreate()
FrameBuffer::~FrameBuffer()
{
if(m_fbo != 0)
assert(!g_app->isTermianted());
if(g_graphics.ok() && m_fbo != 0)
glDeleteFramebuffers(1, &m_fbo);
}
void FrameBuffer::resize(const Size& size)
{
if(!size.isValid())
return;
assert(size.isValid());
if(m_texture && m_texture->getSize() == size)
return;

View File

@@ -28,9 +28,12 @@
class FrameBuffer
{
public:
protected:
FrameBuffer();
FrameBuffer(const Size& size);
friend class FrameBufferManager;
public:
virtual ~FrameBuffer();
void resize(const Size& size);

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "framebuffermanager.h"
FrameBufferManager g_framebuffers;
void FrameBufferManager::init()
{
m_temporaryFramebuffer = FrameBufferPtr(new FrameBuffer());
}
void FrameBufferManager::terminate()
{
m_framebuffers.clear();
m_temporaryFramebuffer = nullptr;
}
FrameBufferPtr FrameBufferManager::createFrameBuffer()
{
FrameBufferPtr fbo = FrameBufferPtr(new FrameBuffer());
m_framebuffers.push_back(fbo);
return fbo;
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef FRAMEBUFFERMANAGER_H
#define FRAMEBUFFERMANAGER_H
#include "framebuffer.h"
class FrameBufferManager
{
public:
void init();
void terminate();
void clear();
FrameBufferPtr createFrameBuffer();
const FrameBufferPtr& getTemporaryFrameBuffer() { return m_temporaryFramebuffer; }
protected:
FrameBufferPtr m_temporaryFramebuffer;
std::vector<FrameBufferPtr> m_framebuffers;
};
extern FrameBufferManager g_framebuffers;
#endif

View File

@@ -33,6 +33,8 @@
#include <framework/graphics/graphics.h>
#include <framework/graphics/texture.h>
#include "texturemanager.h"
#include "framebuffermanager.h"
#include <framework/platform/platformwindow.h>
Graphics g_graphics;
@@ -88,13 +90,19 @@ void Graphics::init()
m_alphaBits = 0;
glGetIntegerv(GL_ALPHA_BITS, &m_alphaBits);
m_ok = true;
selectPainterEngine(m_prefferedPainterEngine);
m_emptyTexture = TexturePtr(new Texture);
g_textures.init();
g_framebuffers.init();
}
void Graphics::terminate()
{
g_fonts.releaseFonts();
g_fonts.terminate();
g_framebuffers.terminate();
g_textures.terminate();
#ifdef PAINTER_OGL2
if(g_painterOGL2) {
@@ -112,7 +120,7 @@ void Graphics::terminate()
g_painter = nullptr;
m_emptyTexture.reset();
m_ok = false;
}
bool Graphics::parseOption(const std::string& option)

View File

@@ -51,13 +51,13 @@ public:
int getMaxTextureSize() { return m_maxTextureSize; }
const Size& getViewportSize() { return m_viewportSize; }
TexturePtr& getEmptyTexture() { return m_emptyTexture; }
std::string getVendor() { return (const char*)glGetString(GL_VENDOR); }
std::string getRenderer() { return (const char*)glGetString(GL_RENDERER); }
std::string getVersion() { return (const char*)glGetString(GL_VERSION); }
std::string getExtensions() { return (const char*)glGetString(GL_EXTENSIONS); }
bool ok() { return m_ok; }
bool canUseDrawArrays();
bool canUseShaders();
bool canUseFBO();
@@ -72,10 +72,10 @@ public:
private:
Size m_viewportSize;
TexturePtr m_emptyTexture;
int m_maxTextureSize;
int m_alphaBits;
Boolean<false> m_ok;
Boolean<true> m_useDrawArrays;
Boolean<true> m_useFBO;
Boolean<false> m_useHardwareBuffers;

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2010-2012 OTClient <https://github.com/edubart/otclient>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hardwarebuffer.h"
#include "graphics.h"
#include <framework/application.h>
#include <framework/core/logger.h>
HardwareBuffer::HardwareBuffer(Type type)
{
m_type = type;
m_id = 0;
glGenBuffers(1, &m_id);
if(!m_id)
g_logger.fatal("Unable to create hardware buffer.");
}
HardwareBuffer::~HardwareBuffer()
{
assert(!g_app->isTermianted());
if(g_graphics.ok())
glDeleteBuffers(1, &m_id);
}

View File

@@ -40,15 +40,8 @@ public:
DynamicDraw = GL_DYNAMIC_DRAW
};
HardwareBuffer(Type type) {
m_type = type;
m_id = 0;
glGenBuffers(1, &m_id);
assert(m_id != 0);
}
~HardwareBuffer() {
glDeleteBuffers(1, &m_id);
}
HardwareBuffer(Type type);
~HardwareBuffer();
void bind() { glBindBuffer(m_type, m_id); }
static void unbind(Type type) { glBindBuffer(type, 0); }

View File

@@ -48,12 +48,6 @@ PainterOGL2::PainterOGL2()
PainterShaderProgram::release();
}
PainterOGL2::~PainterOGL2()
{
m_drawTexturedProgram = nullptr;
m_drawSolidColorProgram = nullptr;
}
void PainterOGL2::bind()
{
Painter::bind();

View File

@@ -36,7 +36,6 @@ class PainterOGL2 : public Painter
{
public:
PainterOGL2();
~PainterOGL2();
void bind();
void unbind();

View File

@@ -21,6 +21,9 @@
*/
#include "shader.h"
#include "graphics.h"
#include <framework/application.h>
#include <framework/core/resourcemanager.h>
Shader::Shader(Shader::ShaderType shaderType)
@@ -41,7 +44,9 @@ Shader::Shader(Shader::ShaderType shaderType)
Shader::~Shader()
{
glDeleteShader(m_shaderId);
assert(!g_app->isTermianted());
if(g_graphics.ok())
glDeleteShader(m_shaderId);
}
bool Shader::compileSourceCode(const std::string& sourceCode)

View File

@@ -21,6 +21,9 @@
*/
#include "shaderprogram.h"
#include "graphics.h"
#include <framework/application.h>
GLuint ShaderProgram::m_currentProgram = 0;
@@ -35,7 +38,9 @@ ShaderProgram::ShaderProgram()
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(m_programId);
assert(!g_app->isTermianted());
if(g_graphics.ok())
glDeleteProgram(m_programId);
}
bool ShaderProgram::addShader(const ShaderPtr& shader) {

View File

@@ -25,6 +25,8 @@
#include "framebuffer.h"
#include "image.h"
#include <framework/application.h>
Texture::Texture()
{
m_id = 0;
@@ -77,8 +79,9 @@ Texture::Texture(const ImagePtr& image, bool buildMipmaps)
Texture::~Texture()
{
assert(!g_app->isTermianted());
// free texture from gl memory
if(m_id > 0)
if(g_graphics.ok() && m_id != 0)
glDeleteTextures(1, &m_id);
}

View File

@@ -30,6 +30,26 @@
TextureManager g_textures;
void TextureManager::init()
{
m_emptyTexture = TexturePtr(new Texture);
}
void TextureManager::terminate()
{
#ifndef NDEBUG
// check for leaks
int refs = 0;
for(const auto& it : m_textures)
if(it.second.use_count() > 1)
refs++;
if(refs > 0)
g_logger.debug(stdext::format("%d textures references left", refs));
#endif
m_textures.clear();
m_emptyTexture = nullptr;
}
TexturePtr TextureManager::getTexture(const std::string& fileName)
{
TexturePtr texture;
@@ -59,7 +79,7 @@ TexturePtr TextureManager::getTexture(const std::string& fileName)
texture = loadPNG(fin);
} catch(stdext::exception& e) {
g_logger.error(stdext::format("unable to load texture '%s': %s", fileName, e.what()));
texture = g_graphics.getEmptyTexture();
texture = g_textures.getEmptyTexture();
}
if(texture)

View File

@@ -28,12 +28,17 @@
class TextureManager
{
public:
TexturePtr getTexture(const std::string& fileName);
void init();
void terminate();
static TexturePtr loadPNG(std::stringstream& file);
TexturePtr getTexture(const std::string& fileName);
const TexturePtr& getEmptyTexture() { return m_emptyTexture; }
private:
TexturePtr loadPNG(std::stringstream& file);
std::unordered_map<std::string, TextureWeakPtr> m_textures;
TexturePtr m_emptyTexture;
};
extern TextureManager g_textures;