Browse Source

Configurable max work time in ms per frame for finishing background loaded resources, and for non-threaded work in WorkQueue. Fix iteration bug if finishing several background loaded resources in one go.

Lasse Öörni 11 years ago
parent
commit
8ab908b1c9

+ 3 - 4
Source/Engine/Core/WorkQueue.cpp

@@ -32,8 +32,6 @@
 namespace Urho3D
 {
 
-const unsigned MAX_NONTHREADED_WORK_USEC = 5000;
-
 /// Worker thread managed by the work queue.
 class WorkerThread : public Thread, public RefCounted
 {
@@ -69,7 +67,8 @@ WorkQueue::WorkQueue(Context* context) :
     pausing_(false),
     paused_(false),
     tolerance_(10),
-    lastSize_(0)
+    lastSize_(0),
+    maxNonThreadedWorkMs_(5)
 {
     SubscribeToEvent(E_BEGINFRAME, HANDLER(WorkQueue, HandleBeginFrame));
 }
@@ -343,7 +342,7 @@ void WorkQueue::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
         
         HiresTimer timer;
         
-        while (!queue_.Empty() && timer.GetUSec(false) < MAX_NONTHREADED_WORK_USEC)
+        while (!queue_.Empty() && timer.GetUSec(false) < maxNonThreadedWorkMs_ * 1000)
         {
             WorkItem* item = queue_.Front();
             queue_.PopFront();

+ 6 - 0
Source/Engine/Core/WorkQueue.h

@@ -98,6 +98,8 @@ public:
     void Complete(unsigned priority);
     /// Set the pool telerance before it starts deleting pool items.
     void SetTolerance(int tolerance) { tolerance_ = tolerance; }
+    /// Set how many milliseconds maximum per frame to spend on low-priority work, when there are no worker threads.
+    void SetNonThreadedWorkMs(int ms) { maxNonThreadedWorkMs_ = Max(ms, 1); }
     
     /// Return number of worker threads.
     unsigned GetNumThreads() const { return threads_.Size(); }
@@ -105,6 +107,8 @@ public:
     bool IsCompleted(unsigned priority) const;
     /// Return the pool tolerance.
     int GetTolerance() const { return tolerance_; }
+    /// Return how many milliseconds maximum to spend on non-threaded low-priority work.
+    int GetNonThreadedWorkMs() const { return maxNonThreadedWorkMs_; }
     
 private:
     /// Process work items until shut down. Called by the worker threads.
@@ -136,6 +140,8 @@ private:
     int tolerance_;
     /// Last size of the shared pool.
     unsigned lastSize_;
+    /// Maximum milliseconds per frame to spend on low-priority work, when there are no worker threads.
+    int maxNonThreadedWorkMs_;
 };
 
 }

+ 6 - 3
Source/Engine/LuaScript/pkgs/Resource/ResourceCache.pkg

@@ -11,6 +11,7 @@ class ResourceCache
     void SetAutoReloadResources(bool enable);
     void SetReturnFailedResources(bool enable);
     void SetSearchPackagesFirst(bool value);
+    void SetFinishBackgroundResourcesMs(int ms);
 
     tolua_outside File* ResourceCacheGetFile @ GetFile(const String name);
 
@@ -27,16 +28,18 @@ class ResourceCache
     bool GetAutoReloadResources() const;
     bool GetReturnFailedResources() const;
     bool GetSearchPackagesFirst() const;
+    int GetFinishBackgroundResourcesMs() const;
 
     String GetPreferredResourceDir(const String path) const;
     String SanitateResourceName(const String name) const;
     String SanitateResourceDirName(const String name) const;
 
     tolua_readonly tolua_property__get_set unsigned totalMemoryUse;
-    tolua_readonly tolua_property__get_set bool autoReloadResources;
-    tolua_readonly tolua_property__get_set bool returnFailedResources;
-    tolua_readonly tolua_property__get_set bool searchPackagesFirst;
+    tolua_property__get_set bool autoReloadResources;
+    tolua_property__get_set bool returnFailedResources;
+    tolua_property__get_set bool searchPackagesFirst;
     tolua_readonly tolua_property__get_set unsigned numBackgroundLoadResources;
+    tolua_property__get_set int finishBackgroundResourcesMs;
 };
 
 ResourceCache* GetCache();

+ 9 - 10
Source/Engine/Resource/ResourceCache.cpp

@@ -42,8 +42,6 @@
 namespace Urho3D
 {
 
-const unsigned MAX_FINISH_RESOURCES_USEC = 5000;
-
 static const char* checkDirs[] = {
     "Fonts",
     "Materials",
@@ -69,7 +67,8 @@ ResourceCache::ResourceCache(Context* context) :
     Object(context),
     autoReloadResources_(false),
     returnFailedResources_(false),
-    searchPackagesFirst_(true)
+    searchPackagesFirst_(true),
+    finishBackgroundResourcesMs_(5)
 {
     // Register Resource library object factories
     RegisterResourceLibrary(context_);
@@ -1093,18 +1092,18 @@ void ResourceCache::HandleBeginFrame(StringHash eventType, VariantMap& eventData
         HiresTimer timer;
 
         for (HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i = backgroundLoadQueue_.Begin();
-            i != backgroundLoadQueue_.End(); ++i)
+            i != backgroundLoadQueue_.End();)
         {
             Resource* resource = i->second_.resource_;
             unsigned numDeps = i->second_.dependencies_.Size();
             AsyncLoadState state = resource->GetAsyncLoadState();
             if (numDeps > 0 || state == ASYNC_QUEUED || state == ASYNC_LOADING)
-                continue;
+                ++i;
             else
-                FinishBackgroundLoading(i);
+                i = FinishBackgroundLoading(i);
 
-            // Break when certain time passed to avoid bogging down the framerate
-            if (timer.GetUSec(false) >= MAX_FINISH_RESOURCES_USEC)
+            // Break when the configured time passed to avoid bogging down the framerate
+            if (timer.GetUSec(false) >= finishBackgroundResourcesMs_ * 1000)
                 break;
         }
     }
@@ -1143,7 +1142,7 @@ File* ResourceCache::SearchPackages(const String& nameIn)
     return 0;
 }
 
-void ResourceCache::FinishBackgroundLoading(HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i)
+HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator ResourceCache::FinishBackgroundLoading(HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i)
 {
     BackgroundLoadItem& item = i->second_;
     Resource* resource = i->second_.resource_;
@@ -1203,7 +1202,7 @@ void ResourceCache::FinishBackgroundLoading(HashMap<Pair<StringHash, StringHash>
     // Finally remove the background queue item
     {
         MutexLock lock(backgroundLoadMutex_);
-        backgroundLoadQueue_.Erase(i);
+        return backgroundLoadQueue_.Erase(i);
     }
 }
 

+ 8 - 2
Source/Engine/Resource/ResourceCache.h

@@ -115,6 +115,8 @@ public:
     void SetReturnFailedResources(bool enable);
     /// Define whether when getting resources should check package files or directories first. True for packages, false for directories.
     void SetSearchPackagesFirst(bool value) { searchPackagesFirst_ = value; }
+    /// Set how many milliseconds maximum per frame to spend on finishing background loaded resources.
+    void SetFinishBackgroundResourcesMs(int ms) { finishBackgroundResourcesMs_ = Max(ms, 1); }
 
     /// Open and return a file from the resource load paths or from inside a package file. If not found, use a fallback search with absolute path. Return null if fails.
     SharedPtr<File> GetFile(const String& name, bool sendEventOnFailure = true);
@@ -162,8 +164,10 @@ public:
     bool GetAutoReloadResources() const { return autoReloadResources_; }
     /// Return whether resources that failed to load are returned.
     bool GetReturnFailedResources() const { return returnFailedResources_; }
-    /// Define whether when getting resources should check package files or directories first.
+    /// Return whether when getting resources should check package files or directories first.
     bool GetSearchPackagesFirst() const { return searchPackagesFirst_; }
+    /// Return how many milliseconds maximum to spend on finishing background loaded resources.
+    int GetFinishBackgroundResourcesMs() const { return finishBackgroundResourcesMs_; }
 
     /// Return either the path itself or its parent, based on which of them has recognized resource subdirectories.
     String GetPreferredResourceDir(const String& path) const;
@@ -192,7 +196,7 @@ private:
     /// Search resource packages for file.
     File* SearchPackages(const String& nameIn);
     /// Finish the loading of a background loaded resource.
-    void FinishBackgroundLoading(HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i);
+    HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator FinishBackgroundLoading(HashMap<Pair<StringHash, StringHash>, BackgroundLoadItem>::Iterator i);
     
     /// Mutex for thread-safe access to the resource directories, resource packages and resource dependencies.
     mutable Mutex resourceMutex_;
@@ -216,6 +220,8 @@ private:
     bool returnFailedResources_;
     /// Search priority flag.
     bool searchPackagesFirst_;
+    /// How many milliseconds maximum per frame to spend on finishing background loaded resources.
+    int finishBackgroundResourcesMs_;
 };
 
 template <class T> T* ResourceCache::GetResource(const String& name, bool sendEventOnFailure)

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

@@ -134,6 +134,8 @@ static void RegisterResourceCache(asIScriptEngine* engine)
     engine->RegisterObjectMethod("ResourceCache", "bool get_autoReloadResources() const", asMETHOD(ResourceCache, GetAutoReloadResources), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "void set_returnFailedResources(bool)", asMETHOD(ResourceCache, SetReturnFailedResources), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "bool get_returnFailedResources() const", asMETHOD(ResourceCache, GetReturnFailedResources), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ResourceCache", "void set_finishBackgroundResourcesMs(int)", asMETHOD(ResourceCache, SetFinishBackgroundResourcesMs), asCALL_THISCALL);
+    engine->RegisterObjectMethod("ResourceCache", "int get_finishBackgroundResourcesMs() const", asMETHOD(ResourceCache, GetFinishBackgroundResourcesMs), asCALL_THISCALL);
     engine->RegisterObjectMethod("ResourceCache", "uint get_numBackgroundLoadResources() const", asMETHOD(ResourceCache, GetNumBackgroundLoadResources), asCALL_THISCALL);
     engine->RegisterGlobalFunction("ResourceCache@+ get_resourceCache()", asFUNCTION(GetResourceCache), asCALL_CDECL);
     engine->RegisterGlobalFunction("ResourceCache@+ get_cache()", asFUNCTION(GetResourceCache), asCALL_CDECL);