Improved ResourceListeners

Former-commit-id: 8016c23cb75aab94762a1e2838dbbcac2093119b
This commit is contained in:
Lynix 2013-08-09 16:28:07 +02:00
parent 4b1a6cc09e
commit d4cff9946e
11 changed files with 74 additions and 71 deletions

View File

@ -9,7 +9,7 @@
#include <Nazara/Prerequesites.hpp> #include <Nazara/Prerequesites.hpp>
#include <atomic> #include <atomic>
#include <set> #include <unordered_map>
#if NAZARA_CORE_THREADSAFE && NAZARA_THREADSAFETY_RESOURCE #if NAZARA_CORE_THREADSAFE && NAZARA_THREADSAFETY_RESOURCE
#include <Nazara/Core/ThreadSafety.hpp> #include <Nazara/Core/ThreadSafety.hpp>
@ -19,23 +19,6 @@
class NzResourceListener; class NzResourceListener;
struct NzResourceEntry
{
NzResourceEntry(NzResourceListener* resourceListener, int i = 0) :
listener(resourceListener),
index(i)
{
}
bool operator<(const NzResourceEntry& rhs) const
{
return listener < rhs.listener;
}
NzResourceListener* listener;
int index;
};
class NAZARA_API NzResource class NAZARA_API NzResource
{ {
public: public:
@ -59,16 +42,13 @@ class NAZARA_API NzResource
void NotifyDestroy(); void NotifyDestroy();
private: private:
void EnsureResourceListenerUpdate() const;
NazaraMutexAttrib(m_mutex, mutable) NazaraMutexAttrib(m_mutex, mutable)
// Je fais précéder le nom par 'resource' pour éviter les éventuels conflits de noms // Je fais précéder le nom par 'resource' pour éviter les éventuels conflits de noms
mutable std::set<NzResourceEntry> m_resourceListeners; mutable std::unordered_map<NzResourceListener*, int> m_resourceListeners;
mutable std::set<NzResourceEntry> m_resourceListenersCache;
mutable bool m_resourceListenerUpdated;
std::atomic_bool m_resourcePersistent; std::atomic_bool m_resourcePersistent;
mutable std::atomic_uint m_resourceReferenceCount; mutable std::atomic_uint m_resourceReferenceCount;
bool m_resourceListenersLocked;
}; };
#endif // NAZARA_RESOURCE_HPP #endif // NAZARA_RESOURCE_HPP

View File

@ -17,8 +17,8 @@ class NAZARA_API NzResourceListener
NzResourceListener() = default; NzResourceListener() = default;
virtual ~NzResourceListener(); virtual ~NzResourceListener();
virtual void OnResourceCreated(const NzResource* resource, int index); virtual bool OnResourceCreated(const NzResource* resource, int index);
virtual void OnResourceDestroy(const NzResource* resource, int index); virtual bool OnResourceDestroy(const NzResource* resource, int index);
virtual void OnResourceReleased(const NzResource* resource, int index); virtual void OnResourceReleased(const NzResource* resource, int index);
}; };

View File

@ -38,7 +38,7 @@ class NAZARA_API NzForwardRenderQueue : public NzAbstractRenderQueue, NzResource
void Sort(const NzCamera& camera); void Sort(const NzCamera& camera);
private: private:
void OnResourceDestroy(const NzResource* resource, int index); bool OnResourceDestroy(const NzResource* resource, int index) override;
struct ModelMaterialComparator struct ModelMaterialComparator
{ {

View File

@ -51,7 +51,7 @@ class NAZARA_API NzRenderTexture : public NzRenderTarget, NzResourceListener, Nz
void Desactivate() const override; void Desactivate() const override;
private: private:
void OnResourceDestroy(const NzResource* resource, int index) override; bool OnResourceDestroy(const NzResource* resource, int index) override;
NzRenderTextureImpl* m_impl = nullptr; NzRenderTextureImpl* m_impl = nullptr;
}; };

View File

@ -12,15 +12,16 @@
NzResource::NzResource(bool persistent) : NzResource::NzResource(bool persistent) :
m_resourcePersistent(persistent), m_resourcePersistent(persistent),
m_resourceReferenceCount(0) m_resourceReferenceCount(0),
m_resourceListenersLocked(false)
{ {
} }
NzResource::~NzResource() NzResource::~NzResource()
{ {
EnsureResourceListenerUpdate(); m_resourceListenersLocked = true;
for (const NzResourceEntry& entry : m_resourceListenersCache) for (auto& pair : m_resourceListeners)
entry.listener->OnResourceReleased(this, entry.index); pair.first->OnResourceReleased(this, pair.second);
#if NAZARA_CORE_SAFE #if NAZARA_CORE_SAFE
if (m_resourceReferenceCount > 0) if (m_resourceReferenceCount > 0)
@ -30,10 +31,11 @@ NzResource::~NzResource()
void NzResource::AddResourceListener(NzResourceListener* listener, int index) const void NzResource::AddResourceListener(NzResourceListener* listener, int index) const
{ {
///DOC: Est ignoré si appelé depuis un évènement
NazaraLock(m_mutex) NazaraLock(m_mutex)
if (m_resourceListeners.insert(NzResourceEntry(listener, index)).second) if (!m_resourceListenersLocked)
m_resourceListenerUpdated = false; m_resourceListeners.insert(std::make_pair(listener, index));
} }
void NzResource::AddResourceReference() const void NzResource::AddResourceReference() const
@ -53,10 +55,11 @@ bool NzResource::IsPersistent() const
void NzResource::RemoveResourceListener(NzResourceListener* listener) const void NzResource::RemoveResourceListener(NzResourceListener* listener) const
{ {
NazaraMutexLock(m_mutex); ///DOC: Est ignoré si appelé depuis un évènement
NazaraLock(m_mutex);
if (m_resourceListeners.erase(listener) != 0) if (!m_resourceListenersLocked)
m_resourceListenerUpdated = false; m_resourceListeners.erase(listener);
} }
bool NzResource::RemoveResourceReference() const bool NzResource::RemoveResourceReference() const
@ -97,26 +100,34 @@ void NzResource::NotifyCreated()
{ {
NazaraLock(m_mutex) NazaraLock(m_mutex)
EnsureResourceListenerUpdate(); m_resourceListenersLocked = true;
for (const NzResourceEntry& entry : m_resourceListenersCache)
entry.listener->OnResourceCreated(this, entry.index); auto it = m_resourceListeners.begin();
while (it != m_resourceListeners.end())
{
if (!it->first->OnResourceCreated(this, it->second))
m_resourceListeners.erase(it++);
else
++it;
}
m_resourceListenersLocked = false;
} }
void NzResource::NotifyDestroy() void NzResource::NotifyDestroy()
{ {
NazaraLock(m_mutex) NazaraLock(m_mutex)
EnsureResourceListenerUpdate(); m_resourceListenersLocked = true;
for (const NzResourceEntry& entry : m_resourceListenersCache)
entry.listener->OnResourceDestroy(this, entry.index); auto it = m_resourceListeners.begin();
while (it != m_resourceListeners.end())
{
if (!it->first->OnResourceDestroy(this, it->second))
m_resourceListeners.erase(it++);
else
++it;
} }
void NzResource::EnsureResourceListenerUpdate() const m_resourceListenersLocked = false;
{
// Déjà bloqué par une mutex
if (!m_resourceListenerUpdated)
{
m_resourceListenersCache = m_resourceListeners;
m_resourceListenerUpdated = true;
}
} }

View File

@ -7,16 +7,20 @@
NzResourceListener::~NzResourceListener() = default; NzResourceListener::~NzResourceListener() = default;
void NzResourceListener::OnResourceCreated(const NzResource* resource, int index) bool NzResourceListener::OnResourceCreated(const NzResource* resource, int index)
{ {
NazaraUnused(resource); NazaraUnused(resource);
NazaraUnused(index); NazaraUnused(index);
return true;
} }
void NzResourceListener::OnResourceDestroy(const NzResource* resource, int index) bool NzResourceListener::OnResourceDestroy(const NzResource* resource, int index)
{ {
NazaraUnused(resource); NazaraUnused(resource);
NazaraUnused(index); NazaraUnused(index);
return true;
} }
void NzResourceListener::OnResourceReleased(const NzResource* resource, int index) void NzResourceListener::OnResourceReleased(const NzResource* resource, int index)

View File

@ -206,7 +206,7 @@ void NzForwardRenderQueue::Sort(const NzCamera& camera)
std::sort(transparentsModels.begin(), transparentsModels.end(), comparator); std::sort(transparentsModels.begin(), transparentsModels.end(), comparator);
} }
void NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int index) bool NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int index)
{ {
switch (index) switch (index)
{ {
@ -231,7 +231,7 @@ void NzForwardRenderQueue::OnResourceDestroy(const NzResource* resource, int ind
} }
} }
resource->RemoveResourceListener(this); return false; // Nous ne voulons plus recevoir d'évènement de cette ressource
} }
bool NzForwardRenderQueue::SkeletalMeshComparator::operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2) bool NzForwardRenderQueue::SkeletalMeshComparator::operator()(const NzSkeletalMesh* subMesh1, const NzSkeletalMesh* subMesh2)

View File

@ -520,7 +520,7 @@ bool NzGLSLProgram::SendVector(int location, const NzVector4f& vector)
return true; return true;
} }
void NzGLSLProgram::OnResourceCreated(const NzResource* resource, int index) bool NzGLSLProgram::OnResourceCreated(const NzResource* resource, int index)
{ {
NazaraUnused(resource); NazaraUnused(resource);
@ -530,7 +530,7 @@ void NzGLSLProgram::OnResourceCreated(const NzResource* resource, int index)
if (it == m_textures.end()) if (it == m_textures.end())
{ {
NazaraInternalError("Invalid index (" + NzString::Number(index) + ')'); NazaraInternalError("Invalid index (" + NzString::Number(index) + ')');
return; return false;
} }
#endif #endif
@ -540,15 +540,17 @@ void NzGLSLProgram::OnResourceCreated(const NzResource* resource, int index)
if (slot.texture != resource) if (slot.texture != resource)
{ {
NazaraInternalError("Wrong texture at location #" + NzString::Number(index)); NazaraInternalError("Wrong texture at location #" + NzString::Number(index));
return; return false;
} }
#endif #endif
slot.enabled = true; slot.enabled = true;
slot.updated = false; slot.updated = false;
return true;
} }
void NzGLSLProgram::OnResourceDestroy(const NzResource* resource, int index) bool NzGLSLProgram::OnResourceDestroy(const NzResource* resource, int index)
{ {
NazaraUnused(resource); NazaraUnused(resource);
@ -558,7 +560,7 @@ void NzGLSLProgram::OnResourceDestroy(const NzResource* resource, int index)
if (it == m_textures.end()) if (it == m_textures.end())
{ {
NazaraInternalError("Invalid index (" + NzString::Number(index) + ')'); NazaraInternalError("Invalid index (" + NzString::Number(index) + ')');
return; return false;
} }
#endif #endif
@ -568,19 +570,19 @@ void NzGLSLProgram::OnResourceDestroy(const NzResource* resource, int index)
if (slot.texture != resource) if (slot.texture != resource)
{ {
NazaraInternalError("Wrong texture at location #" + NzString::Number(index)); NazaraInternalError("Wrong texture at location #" + NzString::Number(index));
return; return false;
} }
#endif #endif
slot.enabled = false; slot.enabled = false;
return true;
} }
void NzGLSLProgram::OnResourceReleased(const NzResource* resource, int index) void NzGLSLProgram::OnResourceReleased(const NzResource* resource, int index)
{ {
if (m_textures.erase(index) == 0) if (m_textures.erase(index) == 0)
NazaraInternalError("Texture " + NzString::Pointer(resource) + " not found"); NazaraInternalError("Texture " + NzString::Pointer(resource) + " not found");
resource->RemoveResourceListener(this);
} }
void NzGLSLProgram::PreLinkage() void NzGLSLProgram::PreLinkage()

View File

@ -60,8 +60,8 @@ class NzGLSLProgram : public NzAbstractShaderProgram, NzResourceListener
bool SendVector(int location, const NzVector4f& vector); bool SendVector(int location, const NzVector4f& vector);
private: private:
void OnResourceCreated(const NzResource* resource, int index) override; bool OnResourceCreated(const NzResource* resource, int index) override;
void OnResourceDestroy(const NzResource* resource, int index) override; bool OnResourceDestroy(const NzResource* resource, int index) override;
void OnResourceReleased(const NzResource* resource, int index) override; void OnResourceReleased(const NzResource* resource, int index) override;
void PreLinkage(); void PreLinkage();
bool PostLinkage(); bool PostLinkage();

View File

@ -324,11 +324,12 @@ void NzRenderTexture::Destroy()
{ {
if (m_impl) if (m_impl)
{ {
bool canFreeFBO = true;
#if NAZARA_RENDERER_SAFE #if NAZARA_RENDERER_SAFE
if (NzContext::GetCurrent() != m_impl->context) if (NzContext::GetCurrent() != m_impl->context)
{ {
NazaraError("RenderTexture can only be used with it's creation context"); NazaraWarning("RenderTexture should be destroyed by it's creation context, this will cause leaks");
return; canFreeFBO = false;
} }
#endif #endif
@ -339,7 +340,7 @@ void NzRenderTexture::Destroy()
if (attachment.isUsed) if (attachment.isUsed)
{ {
if (attachment.isBuffer) if (attachment.isBuffer)
glDeleteRenderbuffers(1, &attachment.buffer); glDeleteRenderbuffers(1, &attachment.buffer); // Les Renderbuffers sont partagés entre les contextes: Ne posera pas de problème
else else
{ {
attachment.texture->SetRenderTexture(nullptr); attachment.texture->SetRenderTexture(nullptr);
@ -348,6 +349,7 @@ void NzRenderTexture::Destroy()
} }
} }
if (canFreeFBO)
glDeleteFramebuffers(1, &m_impl->fbo); glDeleteFramebuffers(1, &m_impl->fbo);
delete m_impl; delete m_impl;
@ -636,11 +638,15 @@ void NzRenderTexture::Desactivate() const
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
} }
void NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index) bool NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index)
{ {
if (resource == m_impl->context) if (resource == m_impl->context)
// Notre context a été détruit, libérons la RenderTexture pour éviter un leak {
// Notre contexte va être détruit, libérons la RenderTexture pour éviter un leak
Destroy(); Destroy();
return false;
}
else else
{ {
// Sinon, c'est une texture // Sinon, c'est une texture
@ -652,5 +658,7 @@ void NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index)
m_impl->checked = false; m_impl->checked = false;
m_impl->drawBuffersUpdated = false; m_impl->drawBuffersUpdated = false;
return true;
} }
} }

View File

@ -128,6 +128,4 @@ void NzStaticMesh::OnResourceReleased(const NzResource* resource, int index)
m_vertexBuffer = nullptr; m_vertexBuffer = nullptr;
else else
NazaraInternalError("Not listening to " + NzString::Pointer(resource)); NazaraInternalError("Not listening to " + NzString::Pointer(resource));
resource->RemoveResourceListener(this);
} }