Browse Source

Improved resource unloading. Make it possible to unload all resource types by partial name at once. Editor unloads unnecessary resources after scene load or clear. Add weak ref check to all resource unloading to avoid shader programs being left without their parent shader.

Lasse Öörni 12 years ago
parent
commit
0fe2469957

+ 6 - 0
Bin/Data/Scripts/Editor/EditorScene.as

@@ -72,6 +72,9 @@ bool ResetScene()
     editorScene.CreateComponent("PhysicsWorld");
     editorScene.CreateComponent("DebugRenderer");
 
+    // Release resources that became unused after the scene clear
+    cache.ReleaseAllResources(false);
+
     sceneModified = false;
     runUpdate = false;
 
@@ -163,6 +166,9 @@ bool LoadScene(const String&in fileName)
     else
         loaded = editorScene.LoadXML(file);
 
+    // Release resources which are not used by the new scene
+    cache.ReleaseAllResources(false);
+
     // Always pause the scene, and do updates manually
     editorScene.updateEnabled = false;
 

+ 2 - 1
Docs/AngelScriptAPI.h

@@ -1449,8 +1449,9 @@ void RemoveResourceDir(const String&);
 void RemovePackageFile(PackageFile, bool = true, bool = false);
 void RemovePackageFile(const String&, bool = true, bool = false);
 void ReleaseResource(const String&, const String&, bool = false);
-void ReleaseResources(const String&, bool = false);
+void ReleaseResources(ShortStringHash, bool = false);
 void ReleaseResources(const String&, const String&, bool = false);
+void ReleaseResources(const String&, bool = false);
 void ReleaseAllResources(bool = false);
 bool ReloadResource(Resource);
 bool Exists(const String&) const;

+ 2 - 1
Docs/ScriptAPI.dox

@@ -1390,8 +1390,9 @@ Methods:
 - void RemovePackageFile(PackageFile@, bool = true, bool = false)
 - void RemovePackageFile(const String&, bool = true, bool = false)
 - void ReleaseResource(const String&, const String&, bool = false)
-- void ReleaseResources(const String&, bool = false)
+- void ReleaseResources(ShortStringHash, bool = false)
 - void ReleaseResources(const String&, const String&, bool = false)
+- void ReleaseResources(const String&, bool = false)
 - void ReleaseAllResources(bool = false)
 - bool ReloadResource(Resource@)
 - bool Exists(const String&) const

+ 55 - 22
Source/Engine/Resource/ResourceCache.cpp

@@ -188,17 +188,13 @@ void ResourceCache::RemovePackageFile(const String& fileName, bool releaseResour
 
 void ResourceCache::ReleaseResource(ShortStringHash type, const String& name, bool force)
 {
-    ReleaseResource(type, StringHash(name), force);
-}
-
-void ResourceCache::ReleaseResource(ShortStringHash type, StringHash nameHash, bool force)
-{
+    StringHash nameHash(name);
     const SharedPtr<Resource>& existingRes = FindResource(type, nameHash);
     if (!existingRes)
         return;
     
     // If other references exist, do not release, unless forced
-    if (existingRes.Refs() == 1 || force)
+    if ((existingRes.Refs() == 1 && existingRes.WeakRefs() == 0) || force)
     {
         resourceGroups_[type].resources_.Erase(nameHash);
         UpdateResourceGroup(type);
@@ -217,7 +213,7 @@ void ResourceCache::ReleaseResources(ShortStringHash type, bool force)
         {
             HashMap<StringHash, SharedPtr<Resource> >::Iterator current = j++;
             // If other references exist, do not release, unless forced
-            if (current->second_.Refs() == 1 || force)
+            if ((current->second_.Refs() == 1 && current->second_.WeakRefs() == 0) || force)
             {
                 i->second_.resources_.Erase(current);
                 released = true;
@@ -243,7 +239,7 @@ void ResourceCache::ReleaseResources(ShortStringHash type, const String& partial
             if (current->second_->GetName().Contains(partialName))
             {
                 // If other references exist, do not release, unless forced
-                if (current->second_.Refs() == 1 || force)
+                if ((current->second_.Refs() == 1 && current->second_.WeakRefs() == 0) || force)
                 {
                     i->second_.resources_.Erase(current);
                     released = true;
@@ -256,26 +252,63 @@ void ResourceCache::ReleaseResources(ShortStringHash type, const String& partial
         UpdateResourceGroup(type);
 }
 
+void ResourceCache::ReleaseResources(const String& partialName, bool force)
+{
+    // Some resources refer to others, like materials to textures. Release twice to ensure these get released.
+    // This is not necessary if forcing release
+    unsigned repeat = force ? 1 : 2;
+    
+    while (repeat--)
+    {
+        for (HashMap<ShortStringHash, ResourceGroup>::Iterator i = resourceGroups_.Begin(); i != resourceGroups_.End(); ++i)
+        {
+            bool released = false;
+            
+            for (HashMap<StringHash, SharedPtr<Resource> >::Iterator j = i->second_.resources_.Begin();
+                j != i->second_.resources_.End();)
+            {
+                HashMap<StringHash, SharedPtr<Resource> >::Iterator current = j++;
+                if (current->second_->GetName().Contains(partialName))
+                {
+                    // If other references exist, do not release, unless forced
+                    if ((current->second_.Refs() == 1 && current->second_.WeakRefs() == 0) || force)
+                    {
+                        i->second_.resources_.Erase(current);
+                        released = true;
+                    }
+                }
+            }
+            if (released)
+                UpdateResourceGroup(i->first_);
+        }
+    }
+}
+
 void ResourceCache::ReleaseAllResources(bool force)
 {
-    for (HashMap<ShortStringHash, ResourceGroup>::Iterator i = resourceGroups_.Begin();
-        i != resourceGroups_.End(); ++i)
+    unsigned repeat = force ? 1 : 2;
+    
+    while (repeat--)
     {
-        bool released = false;
-        
-        for (HashMap<StringHash, SharedPtr<Resource> >::Iterator j = i->second_.resources_.Begin();
-            j != i->second_.resources_.End();)
+        for (HashMap<ShortStringHash, ResourceGroup>::Iterator i = resourceGroups_.Begin();
+            i != resourceGroups_.End(); ++i)
         {
-            HashMap<StringHash, SharedPtr<Resource> >::Iterator current = j++;
-            // If other references exist, do not release, unless forced
-            if ((current->second_.Refs() == 1 && current->second_.WeakRefs() == 0) || force)
+            bool released = false;
+            
+            for (HashMap<StringHash, SharedPtr<Resource> >::Iterator j = i->second_.resources_.Begin();
+                j != i->second_.resources_.End();)
             {
-                i->second_.resources_.Erase(current);
-                released = true;
+                HashMap<StringHash, SharedPtr<Resource> >::Iterator current = j++;
+                // If other references exist, do not release, unless forced
+                if ((current->second_.Refs() == 1 && current->second_.WeakRefs() == 0) || force)
+                {
+                    i->second_.resources_.Erase(current);
+                    released = true;
+                }
             }
+            if (released)
+                UpdateResourceGroup(i->first_);
         }
-        if (released)
-            UpdateResourceGroup(i->first_);
     }
 }
 
@@ -637,7 +670,7 @@ void ResourceCache::ReleasePackageResources(PackageFile* package, bool force)
             if (k != j->second_.resources_.End())
             {
                 // If other references exist, do not release, unless forced
-                if (k->second_.Refs() == 1 || force)
+                if ((k->second_.Refs() == 1 && k->second_.WeakRefs() == 0) || force)
                 {
                     j->second_.resources_.Erase(k);
                     affectedGroups.Insert(j->first_);

+ 3 - 3
Source/Engine/Resource/ResourceCache.h

@@ -75,13 +75,13 @@ public:
     void RemovePackageFile(const String& fileName, bool releaseResources = true, bool forceRelease = false);
     /// Release a resource by name.
     void ReleaseResource(ShortStringHash type, const String& name, bool force = false);
-    /// Release a resource by name hash.
-    void ReleaseResource(ShortStringHash type, StringHash nameHash, bool force = false);
     /// Release all resources of a specific type.
     void ReleaseResources(ShortStringHash type, bool force = false);
     /// Release resources of a specific type and partial name.
     void ReleaseResources(ShortStringHash type, const String& partialName, bool force = false);
-    /// Release all resources.
+    /// Release resources of all types by partial name.
+    void ReleaseResources(const String& partialName, bool force = false);
+    /// Release all resources. When called with the force flag false, releases all currently unused resources.
     void ReleaseAllResources(bool force = false);
     /// Reload a resource. Return false and release it if fails.
     bool ReloadResource(Resource* resource);

+ 2 - 6
Source/Engine/Script/ResourceAPI.cpp

@@ -56,11 +56,6 @@ static void ResourceCacheReleaseResource(const String& type, const String& name,
     ptr->ReleaseResource(type, name, force);
 }
 
-static void ResourceCacheReleaseResources(const String& type, bool force, ResourceCache* ptr)
-{
-    ptr->ReleaseResources(type, force);
-}
-
 static void ResourceCacheReleaseResourcesPartial(const String& type, const String& partialName, bool force, ResourceCache* ptr)
 {
     ptr->ReleaseResources(type, partialName, force);
@@ -106,8 +101,9 @@ static void RegisterResourceCache(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ResourceCache", "void RemovePackageFile(PackageFile@+, bool releaseResources = true, bool forceRelease = false)", asMETHODPR(ResourceCache, RemovePackageFile, (PackageFile*, bool, bool), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "void RemovePackageFile(const String&in, bool releaseResources = true, bool forceRelease = false)", asMETHODPR(ResourceCache, RemovePackageFile, (const String&, bool, bool), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "void ReleaseResource(const String&in, const String&in, bool force = false)", asFUNCTION(ResourceCacheReleaseResource), asCALL_CDECL_OBJLAST);
-    engine->RegisterObjectMethod("ResourceCache", "void ReleaseResources(const String&in, bool force = false)", asFUNCTION(ResourceCacheReleaseResources), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ResourceCache", "void ReleaseResources(ShortStringHash, bool force = false)", asMETHODPR(ResourceCache, ReleaseResources, (ShortStringHash, bool), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "void ReleaseResources(const String&in, const String&in, bool force = false)", asFUNCTION(ResourceCacheReleaseResourcesPartial), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("ResourceCache", "void ReleaseResources(const String&in, bool force = false)", asMETHODPR(ResourceCache, ReleaseResources, (const String&, bool), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "void ReleaseAllResources(bool force = false)", asMETHOD(ResourceCache, ReleaseAllResources), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "bool ReloadResource(Resource@+)", asMETHOD(ResourceCache, ReloadResource), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "bool Exists(const String&in) const", asMETHODPR(ResourceCache, Exists, (const String&) const, bool), asCALL_THISCALL);