From 7243881de53d5b35296dcc7b2d2e6b9507b5dbbe Mon Sep 17 00:00:00 2001 From: baldurk Date: Sun, 30 Nov 2014 16:23:11 +0000 Subject: [PATCH] Ensure parent refs are deleted before force-deleting resource records * This most commonly happens with shaders and programs. A program record takes a reference on shader records when they are attached and linked, then a shader can be orphaned with only that reference remaining if the user code detaches and deletes it. * Previously we would go through, force-delete the shader, then when we force-delete the program things would explode since it tries to decrement the refcount on the shader and it becomes -1. So now we make all records remove their parents (which might delete their parents), before we force delete them. --- renderdoc/driver/gl/gl_manager.h | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/renderdoc/driver/gl/gl_manager.h b/renderdoc/driver/gl/gl_manager.h index cdb42130c..b012c359e 100644 --- a/renderdoc/driver/gl/gl_manager.h +++ b/renderdoc/driver/gl/gl_manager.h @@ -42,6 +42,40 @@ class GLResourceManager : public ResourceManager void Shutdown() { + // there's a bit of a dependency issue here. We're essentially forcibly deleting/garbage collecting + // all the resource records. In some cases, we might have a parent->child type relationship where + // the only reference on the parent is from the child. If we delete the parent before the child, + // when the child destructs and tries to delete the parent things will go badly. + // We want to avoid keeping a reference ourselves on all records since that would cause difficulties + // during normal lifetime, so instead we just ask all records to release their references on parents + // before deleting them. + + // special care is taken since the act of freeing parents will by design potentially modify the + // container. Since this is shutdown, we take the simple & naive approach of simply restarting the + // loop whenever we detect the size changing. FreeParents() is a safe operation to perform on records + // that have already freed their parents. + { + auto it = m_GLResourceRecords.begin(); + + for(size_t i=0; it != m_GLResourceRecords.end();) + { + size_t prevSize = m_GLResourceRecords.size(); + it->second->FreeParents(this); + + // collection modified, restart loop + if(prevSize != m_GLResourceRecords.size()) + { + i = 0; + it = m_GLResourceRecords.begin(); + continue; + } + + // collection not modified, continue + i++; + it++; + } + } + while(!m_GLResourceRecords.empty()) { auto it = m_GLResourceRecords.begin();