Added OpenGL::Delete[FrameBuffer|VertexArray]

Also renamed OpenGL::OnContextChange to OnContextChanged (since it
happens after the context change)
Also improved RenderTexture implementation


Former-commit-id: d845b1405294dd3aa134d392585069bbb28a77a3
This commit is contained in:
Lynix 2014-04-25 12:38:53 +02:00
parent a3f877daf1
commit 7ac3fee3a5
4 changed files with 70 additions and 27 deletions

View File

@ -86,9 +86,11 @@ class NAZARA_API NzOpenGL
static void BindViewport(const NzRecti& viewport); static void BindViewport(const NzRecti& viewport);
static void DeleteBuffer(nzBufferType type, GLuint id); static void DeleteBuffer(nzBufferType type, GLuint id);
static void DeleteFrameBuffer(const NzContext* context, GLuint id);
static void DeleteProgram(GLuint id); static void DeleteProgram(GLuint id);
static void DeleteSampler(GLuint id); static void DeleteSampler(GLuint id);
static void DeleteTexture(GLuint id); static void DeleteTexture(GLuint id);
static void DeleteVertexArray(const NzContext* context, GLuint id);
static GLuint GetCurrentBuffer(nzBufferType type); static GLuint GetCurrentBuffer(nzBufferType type);
static GLuint GetCurrentProgram(); static GLuint GetCurrentProgram();
@ -149,7 +151,7 @@ class NAZARA_API NzOpenGL
static GLenum TextureTargetProxy[nzImageType_Max+1]; static GLenum TextureTargetProxy[nzImageType_Max+1];
private: private:
static void OnContextChange(const NzContext* newContext); static void OnContextChanged(const NzContext* newContext);
static void OnContextDestruction(const NzContext* context); static void OnContextDestruction(const NzContext* context);
}; };

View File

@ -248,7 +248,7 @@ bool NzContext::SetActive(bool active) const
currentContext = nullptr; currentContext = nullptr;
} }
NzOpenGL::OnContextChange(currentContext); NzOpenGL::OnContextChanged(currentContext);
return true; return true;
} }

View File

@ -63,8 +63,15 @@ namespace
#endif #endif
} }
enum GarbageResourceType
{
GarbageResourceType_FrameBuffer,
GarbageResourceType_VertexArray
};
struct ContextStates struct ContextStates
{ {
std::vector<std::pair<GarbageResourceType, GLuint>> garbage; // Les ressources à supprimer dès que possible
GLuint buffersBinding[nzBufferType_Max+1] = {0}; GLuint buffersBinding[nzBufferType_Max+1] = {0};
GLuint currentProgram = 0; GLuint currentProgram = 0;
GLuint samplers[32] = {0}; // 32 est pour l'instant la plus haute limite (GL_TEXTURE31) GLuint samplers[32] = {0}; // 32 est pour l'instant la plus haute limite (GL_TEXTURE31)
@ -496,6 +503,15 @@ void NzOpenGL::DeleteBuffer(nzBufferType type, GLuint id)
s_contextStates->buffersBinding[type] = 0; s_contextStates->buffersBinding[type] = 0;
} }
void NzOpenGL::DeleteFrameBuffer(const NzContext* context, GLuint id)
{
// Si le contexte est actif, ne nous privons pas
if (NzContext::GetCurrent() == context)
glDeleteFramebuffers(1, &id);
else
s_contexts[context].garbage.emplace_back(GarbageResourceType_FrameBuffer, id);
}
void NzOpenGL::DeleteProgram(GLuint id) void NzOpenGL::DeleteProgram(GLuint id)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -555,6 +571,15 @@ void NzOpenGL::DeleteTexture(GLuint id)
} }
} }
void NzOpenGL::DeleteVertexArray(const NzContext* context, GLuint id)
{
// Si le contexte est actif, ne nous privons pas
if (NzContext::GetCurrent() == context)
glDeleteFramebuffers(1, &id);
else
s_contexts[context].garbage.emplace_back(GarbageResourceType_VertexArray, id);
}
GLuint NzOpenGL::GetCurrentBuffer(nzBufferType type) GLuint NzOpenGL::GetCurrentBuffer(nzBufferType type)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -1778,9 +1803,27 @@ void NzOpenGL::Uninitialize()
} }
} }
void NzOpenGL::OnContextChange(const NzContext* newContext) void NzOpenGL::OnContextChanged(const NzContext* newContext)
{ {
s_contextStates = (newContext) ? &s_contexts[newContext] : nullptr; s_contextStates = (newContext) ? &s_contexts[newContext] : nullptr;
if (s_contextStates)
{
// On supprime les éventuelles ressources mortes-vivantes (Qui ne peuvent être libérées que dans notre contexte)
for (std::pair<GarbageResourceType, GLuint>& pair : s_contextStates->garbage)
{
switch (pair.first)
{
case GarbageResourceType_FrameBuffer:
glDeleteFramebuffers(1, &pair.second);
break;
case GarbageResourceType_VertexArray:
glDeleteVertexArrays(1, &pair.second);
break;
}
}
s_contextStates->garbage.clear();
}
} }
void NzOpenGL::OnContextDestruction(const NzContext* context) void NzOpenGL::OnContextDestruction(const NzContext* context)

View File

@ -3,6 +3,7 @@
// For conditions of distribution and use, see copyright notice in Config.hpp // For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Renderer/RenderTexture.hpp> #include <Nazara/Renderer/RenderTexture.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <Nazara/Renderer/Context.hpp> #include <Nazara/Renderer/Context.hpp>
#include <Nazara/Renderer/OpenGL.hpp> #include <Nazara/Renderer/OpenGL.hpp>
@ -325,33 +326,38 @@ bool NzRenderTexture::Create(bool lock)
} }
#endif #endif
NzRenderTextureImpl* impl = new NzRenderTextureImpl; std::unique_ptr<NzRenderTextureImpl> impl(new NzRenderTextureImpl);
impl->context = NzContext::GetCurrent();
impl->context->AddResourceListener(this);
impl->fbo = 0; impl->fbo = 0;
glGenFramebuffers(1, &impl->fbo); glGenFramebuffers(1, &impl->fbo);
if (!impl->fbo) if (!impl->fbo)
{ {
delete impl;
NazaraError("Failed to create framebuffer"); NazaraError("Failed to create framebuffer");
return false; return false;
} }
m_impl = impl; m_impl = impl.release();
m_impl->context = NzContext::GetCurrent();
m_impl->context->AddResourceListener(this);
if (lock && !Lock()) if (lock)
{ {
delete impl; // En cas d'exception, la ressource sera quand même libérée
m_impl = nullptr; NzCallOnExit onExit([this] ()
{
Destroy();
});
if (!Lock())
{
NazaraError("Failed to lock render texture"); NazaraError("Failed to lock render texture");
return false; return false;
} }
onExit.Reset();
}
NotifyParametersChange(); NotifyParametersChange();
NotifySizeChange(); NotifySizeChange();
@ -365,15 +371,6 @@ void NzRenderTexture::Destroy()
if (IsActive()) if (IsActive())
NzRenderer::SetTarget(nullptr); NzRenderer::SetTarget(nullptr);
bool canFreeFBO = true;
#if NAZARA_RENDERER_SAFE
if (NzContext::GetCurrent() != m_impl->context)
{
NazaraWarning("RenderTexture should be destroyed by it's creation context, this will cause leaks");
canFreeFBO = false;
}
#endif
m_impl->context->RemoveResourceListener(this); m_impl->context->RemoveResourceListener(this);
for (const Attachment& attachment : m_impl->attachments) for (const Attachment& attachment : m_impl->attachments)
@ -387,10 +384,11 @@ void NzRenderTexture::Destroy()
} }
} }
if (canFreeFBO) // Le FBO devant être supprimé dans son contexte d'origine, nous déléguons sa suppression à la classe OpenGL
glDeleteFramebuffers(1, &m_impl->fbo); // Celle-ci va libérer le FBO dès que possible (la prochaine fois que son contexte d'origine sera actif)
NzOpenGL::DeleteFrameBuffer(m_impl->context, m_impl->fbo);
delete m_impl; delete m_impl; // Enlève également une références sur les Texture/RenderBuffer
m_impl = nullptr; m_impl = nullptr;
} }
} }