Browse Source

Changed WorkItem to a value type to make it easier to construct work queue tasks.

Lasse Öörni 14 years ago
parent
commit
aadc22f05a

+ 0 - 32
Engine/Core/WorkItem.h

@@ -1,32 +0,0 @@
-//
-// Urho3D Engine
-// Copyright (c) 2008-2011 Lasse Öörni
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-//
-
-#pragma once
-
-/// Work queue item base class.
-class WorkItem
-{
-public:
-    /// Do the work. Main thread has index 0, while worker threads have indices 1 - n.
-    virtual void Process(unsigned threadIndex) = 0;
-};

+ 15 - 19
Engine/Core/WorkQueue.cpp

@@ -132,7 +132,7 @@ WorkQueue::~WorkQueue()
     impl_ = 0;
 }
 
-void WorkQueue::AddWorkItem(WorkItem* item)
+void WorkQueue::AddWorkItem(const WorkItem& item)
 {
     if (threads_.Size())
     {
@@ -144,7 +144,7 @@ void WorkQueue::AddWorkItem(WorkItem* item)
             impl_->Signal();
     }
     else
-        item->Process(0);
+        item.workFunction_(&item, 0);
 }
 
 void WorkQueue::Complete()
@@ -154,20 +154,20 @@ void WorkQueue::Complete()
         // Wait for work to finish while also taking work items in the main thread
         for (;;)
         {
-            WorkItem* item = 0;
-            
             queueLock_.Acquire();
             if (!queue_.Empty())
             {
-                item = queue_.Front();
+                WorkItem item = queue_.Front();
                 queue_.PopFront();
+                queueLock_.Release();
+                item.workFunction_(&item, 0);
+            }
+            else
+            {
+                queueLock_.Release();
+                if (numWaiting_ == threads_.Size())
+                    break;
             }
-            queueLock_.Release();
-            
-            if (item)
-                item->Process(0);
-            else if (numWaiting_ == threads_.Size())
-                break;
         }
     }
 }
@@ -185,16 +185,15 @@ bool WorkQueue::IsCompleted()
         return true;
 }
 
-WorkItem* WorkQueue::GetNextWorkItem()
+void WorkQueue::ProcessItems(unsigned threadIndex)
 {
     bool wasWaiting = false;
     
     for (;;)
     {
         if (shutDown_)
-            return 0;
+            return;
         
-        WorkItem* item = 0;
         queueLock_.Acquire();
         if (wasWaiting)
         {
@@ -203,13 +202,10 @@ WorkItem* WorkQueue::GetNextWorkItem()
         }
         if (!queue_.Empty())
         {
-            item = queue_.Front();
+            WorkItem item = queue_.Front();
             queue_.PopFront();
-        }
-        if (item)
-        {
             queueLock_.Release();
-            return item;
+            item.workFunction_(&item, threadIndex);
         }
         else
         {

+ 17 - 5
Engine/Core/WorkQueue.h

@@ -28,9 +28,21 @@
 #include "SpinLock.h"
 
 class WorkerThread;
-class WorkItem;
 class WorkQueueImpl;
 
+/// Work queue item.
+struct WorkItem
+{
+    /// Work function. Called with the work item and thread index (0 = main thread) as parameters.
+    void (*workFunction_)(const WorkItem*, unsigned);
+    /// Data start pointer.
+    void* start_;
+    /// Data end pointer.
+    void* end_;
+    /// Auxiliary data pointer.
+    void* aux_;
+};
+
 /// Work queue subsystem.
 class WorkQueue : public Object
 {
@@ -45,7 +57,7 @@ public:
     ~WorkQueue();
     
     /// Add a work item. If no threads, will process it immediately.
-    void AddWorkItem(WorkItem* item);
+    void AddWorkItem(const WorkItem& item);
     /// Finish all current work items.
     void Complete();
     
@@ -55,15 +67,15 @@ public:
     bool IsCompleted();
     
 private:
-    /// Block until a work item is available and return it. May return null. Called by the worker threads.
-    WorkItem* GetNextWorkItem();
+    /// Process work items until shut down. Called by the worker threads.
+    void ProcessItems(unsigned threadIndex);
     
     /// Work queue implementation. Contains the operating system-specific signaling mechanism.
     WorkQueueImpl* impl_;
     /// Worker threads.
     Vector<SharedPtr<WorkerThread> > threads_;
     /// Work item queue.
-    List<WorkItem*> queue_;
+    List<WorkItem> queue_;
     /// Queue lock.
     SpinLock queueLock_;
     /// Number of waiting threads.

+ 1 - 6
Engine/Core/WorkerThread.cpp

@@ -34,10 +34,5 @@ WorkerThread::WorkerThread(WorkQueue* owner, unsigned index) :
 
 void WorkerThread::ThreadFunction()
 {
-    while (shouldRun_)
-    {
-        WorkItem* item = owner_->GetNextWorkItem();
-        if (item)
-            item->Process(index_);
-    }
+    owner_->ProcessItems(index_);
 }

+ 2 - 1
Engine/Graphics/Drawable.h

@@ -47,6 +47,7 @@ class OcclusionBuffer;
 class Octant;
 class RayOctreeQuery;
 class Zone;
+struct WorkItem;
 
 /// Geometry update type.
 enum UpdateGeometryType
@@ -74,9 +75,9 @@ class Drawable : public Component
 {
     OBJECT(Drawable);
     
-    friend class DrawableUpdate;
     friend class Octant;
     friend class Octree;
+    friend void UpdateDrawablesWork(const WorkItem* item, unsigned threadIndex);
     
 public:
     /// Construct.

+ 22 - 15
Engine/Graphics/Octree.cpp

@@ -40,6 +40,21 @@
 static const float DEFAULT_OCTREE_SIZE = 1000.0f;
 static const int DEFAULT_OCTREE_LEVELS = 8;
 
+void UpdateDrawablesWork(const WorkItem* item, unsigned threadIndex)
+{
+    const FrameInfo& frame = *(reinterpret_cast<FrameInfo*>(item->aux_));
+    Drawable** start = reinterpret_cast<Drawable**>(item->start_);
+    Drawable** end = reinterpret_cast<Drawable**>(item->end_);
+    
+    while (start != end)
+    {
+        Drawable* drawable = *start;
+        drawable->Update(frame);
+        drawable->updateQueued_ = false;
+        ++start;
+    }
+}
+
 inline bool CompareRayQueryResults(const RayQueryResult& lhs, const RayQueryResult& rhs)
 {
     return lhs.distance_ < rhs.distance_;
@@ -446,31 +461,23 @@ void Octree::UpdateDrawables(const FrameInfo& frame)
     PROFILE_MULTIPLE(UpdateDrawable, drawableUpdates_.Size());
     
     Scene* scene = node_->GetScene();
+    WorkQueue* queue = GetSubsystem<WorkQueue>();
     scene->BeginThreadedUpdate();
     
-    WorkQueue* queue = GetSubsystem<WorkQueue>();
-    List<DrawableUpdate>::Iterator item = drawableUpdateItems_.Begin();
     PODVector<Drawable*>::Iterator start = drawableUpdates_.Begin();
-    
     while (start != drawableUpdates_.End())
     {
-        // Create new item to the pool if necessary
-        if (item == drawableUpdateItems_.End())
-        {
-            drawableUpdateItems_.Push(DrawableUpdate());
-            item = --drawableUpdateItems_.End();
-        }
-        
         PODVector<Drawable*>::Iterator end = start;
         while (end - start < DRAWABLES_PER_WORK_ITEM && end != drawableUpdates_.End())
             ++end;
         
-        item->frame_ = &frame;
-        item->start_ = start;
-        item->end_ = end;
-        queue->AddWorkItem(&(*item));
+        WorkItem item;
+        item.workFunction_ = UpdateDrawablesWork;
+        item.start_ = &(*start);
+        item.end_ = &(*end);
+        item.aux_ = const_cast<FrameInfo*>(&frame);
+        queue->AddWorkItem(item);
         
-        ++item;
         start = end;
     }
     

+ 0 - 25
Engine/Graphics/Octree.h

@@ -28,35 +28,12 @@
 #include "SpinLock.h"
 #include "WorkItem.h"
 
-class Drawable;
 class Octree;
 class OctreeQuery;
 class RayOctreeQuery;
 
 static const int NUM_OCTANTS = 8;
 
-/// Drawable update work item.
-class DrawableUpdate : public WorkItem
-{
-public:
-    /// Do the work.
-    virtual void Process(unsigned threadIndex)
-    {
-        for (PODVector<Drawable*>::Iterator i = start_; i != end_; ++i)
-        {
-            (*i)->Update(*frame_);
-            (*i)->updateQueued_ = false;
-        }
-    }
-    
-    /// Frame info.
-    const FrameInfo* frame_;
-    /// Start iterator.
-    PODVector<Drawable*>::Iterator start_;
-    /// End iterator.
-    PODVector<Drawable*>::Iterator end_;
-};
-
 /// %Octree octant
 class Octant
 {
@@ -231,8 +208,6 @@ private:
     PODVector<Drawable*> drawableUpdates_;
     /// Drawable objects that require reinsertion.
     PODVector<Drawable*> drawableReinsertions_;
-    /// Pool for drawable update work items.
-    List<DrawableUpdate> drawableUpdateItems_;
     /// Lock for octree reinsertions.
     SpinLock reinsertionLock_;
     /// Unculled drawables.

+ 20 - 14
Engine/Graphics/View.cpp

@@ -57,6 +57,20 @@ static const Vector3 directions[] =
     Vector3(0.0f, 0.0f, -1.0f)
 };
 
+void UpdateDrawableGeometriesWork(const WorkItem* item, unsigned threadIndex)
+{
+    const FrameInfo& frame = *(reinterpret_cast<FrameInfo*>(item->aux_));
+    Drawable** start = reinterpret_cast<Drawable**>(item->start_);
+    Drawable** end = reinterpret_cast<Drawable**>(item->end_);
+    
+    while (start != end)
+    {
+        Drawable* drawable = *start;
+        drawable->UpdateGeometry(frame);
+        ++start;
+    }
+}
+
 OBJECTTYPESTATIC(View);
 
 View::View(Context* context) :
@@ -607,28 +621,20 @@ void View::UpdateGeometries()
     
     if (threadedGeometries_.Size())
     {
-        List<DrawableGeometryUpdate>::Iterator item = drawableGeometryUpdateItems_.Begin();
         PODVector<Drawable*>::Iterator start = threadedGeometries_.Begin();
-        
         while (start != threadedGeometries_.End())
         {
-            // Create new item to the pool if necessary
-            if (item == drawableGeometryUpdateItems_.End())
-            {
-                drawableGeometryUpdateItems_.Push(DrawableGeometryUpdate());
-                item = --drawableGeometryUpdateItems_.End();
-            }
-            
             PODVector<Drawable*>::Iterator end = start;
             while (end - start < DRAWABLES_PER_WORK_ITEM && end != threadedGeometries_.End())
                 ++end;
             
-            item->frame_ = &frame_;
-            item->start_ = start;
-            item->end_ = end;
-            queue->AddWorkItem(&(*item));
+            WorkItem item;
+            item.workFunction_ = UpdateDrawableGeometriesWork;
+            item.start_ = &(*start);
+            item.end_ = &(*end);
+            item.aux_ = const_cast<FrameInfo*>(&frame_);
+            queue->AddWorkItem(item);
             
-            ++item;
             start = end;
         }
     }

+ 0 - 22
Engine/Graphics/View.h

@@ -24,7 +24,6 @@
 #pragma once
 
 #include "Batch.h"
-#include "Drawable.h"
 #include "HashSet.h"
 #include "List.h"
 #include "Object.h"
@@ -52,25 +51,6 @@ struct GeometryDepthBounds
     float max_;
 };
 
-/// Drawable geometry update work item.
-class DrawableGeometryUpdate : public WorkItem
-{
-public:
-    /// Do the work.
-    virtual void Process(unsigned threadIndex)
-    {
-        for (PODVector<Drawable*>::Iterator i = start_; i != end_; ++i)
-            (*i)->UpdateGeometry(*frame_);
-    }
-    
-    /// Frame info.
-    const FrameInfo* frame_;
-    /// Start iterator.
-    PODVector<Drawable*>::Iterator start_;
-    /// End iterator.
-    PODVector<Drawable*>::Iterator end_;
-};
-
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
 class View : public Object
 {
@@ -248,8 +228,6 @@ private:
     Map<Light*, unsigned> lightQueueIndex_;
     /// Cache for light scissor queries.
     HashMap<Light*, Rect> lightScissorCache_;
-    /// Pool for drawable geometry update work items.
-    List<DrawableGeometryUpdate> drawableGeometryUpdateItems_;
     /// Base pass batches.
     BatchQueue baseQueue_;
     /// Pre-transparent pass batches.