Browse Source

Threaded ray query.

Lasse Öörni 14 years ago
parent
commit
8a57a3ee18

+ 0 - 1
Engine/Engine/GraphicsAPI.cpp

@@ -33,7 +33,6 @@
 #include "Light.h"
 #include "Light.h"
 #include "Material.h"
 #include "Material.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "ParticleEmitter.h"
 #include "ParticleEmitter.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "Technique.h"
 #include "Technique.h"

+ 0 - 1
Engine/Graphics/AnimatedModel.cpp

@@ -37,7 +37,6 @@
 #include "Material.h"
 #include "Material.h"
 #include "MemoryBuffer.h"
 #include "MemoryBuffer.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "ResourceEvents.h"
 #include "ResourceEvents.h"

+ 0 - 1
Engine/Graphics/Drawable.cpp

@@ -27,7 +27,6 @@
 #include "DebugRenderer.h"
 #include "DebugRenderer.h"
 #include "Light.h"
 #include "Light.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "Sort.h"
 #include "Sort.h"
 #include "Zone.h"
 #include "Zone.h"

+ 0 - 2
Engine/Graphics/Light.cpp

@@ -165,8 +165,6 @@ void Light::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 
 
 void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 void Light::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQueryResult>& results)
 {
 {
-    PROFILE(RaycastLight);
-    
     RayQueryLevel level = query.level_;
     RayQueryLevel level = query.level_;
     
     
     switch (level)
     switch (level)

+ 96 - 2
Engine/Graphics/Octree.cpp

@@ -26,7 +26,6 @@
 #include "DebugRenderer.h"
 #include "DebugRenderer.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "Scene.h"
 #include "Scene.h"
 #include "Sort.h"
 #include "Sort.h"
 #include "WorkQueue.h"
 #include "WorkQueue.h"
@@ -39,6 +38,23 @@
 
 
 static const float DEFAULT_OCTREE_SIZE = 1000.0f;
 static const float DEFAULT_OCTREE_SIZE = 1000.0f;
 static const int DEFAULT_OCTREE_LEVELS = 8;
 static const int DEFAULT_OCTREE_LEVELS = 8;
+static const int RAYCASTS_PER_WORK_ITEM = 4;
+
+void RaycastDrawablesWork(const WorkItem* item, unsigned threadIndex)
+{
+    Octree* octree = reinterpret_cast<Octree*>(item->aux_);
+    Drawable** start = reinterpret_cast<Drawable**>(item->start_);
+    Drawable** end = reinterpret_cast<Drawable**>(item->end_);
+    const RayOctreeQuery& query = *octree->rayQuery_;
+    PODVector<RayQueryResult>& results = octree->rayQueryResults_[threadIndex];
+    
+    while (start != end)
+    {
+        Drawable* drawable = *start;
+        drawable->ProcessRayQuery(query, results);
+        ++start;
+    }
+}
 
 
 void UpdateDrawablesWork(const WorkItem* item, unsigned threadIndex)
 void UpdateDrawablesWork(const WorkItem* item, unsigned threadIndex)
 {
 {
@@ -240,6 +256,34 @@ void Octant::GetDrawablesInternal(RayOctreeQuery& query) const
     }
     }
 }
 }
 
 
+void Octant::GetDrawablesOnlyInternal(RayOctreeQuery& query, PODVector<Drawable*>& drawables) const
+{
+    if (!numDrawables_)
+        return;
+    
+    float octantDist = query.ray_.HitDistance(cullingBox_);
+    if (octantDist >= query.maxDistance_)
+        return;
+    
+    for (PODVector<Drawable*>::ConstIterator i = drawables_.Begin(); i != drawables_.End(); ++i)
+    {
+        Drawable* drawable = *i;
+        unsigned drawableFlags = drawable->GetDrawableFlags();
+        
+        if (!(drawable->GetDrawableFlags() & query.drawableFlags_) || !(drawable->GetViewMask() & query.viewMask_) ||
+            !drawable->IsVisible() || (query.shadowCastersOnly_ && !drawable->GetCastShadows()))
+            continue;
+        
+        drawables.Push(drawable);
+    }
+    
+    for (unsigned i = 0; i < NUM_OCTANTS; ++i)
+    {
+        if (children_[i])
+            children_[i]->GetDrawablesOnlyInternal(query, drawables);
+    }
+}
+
 void Octant::Release()
 void Octant::Release()
 {
 {
     if (root_ && this != root_)
     if (root_ && this != root_)
@@ -273,6 +317,8 @@ Octree::Octree(Context* context) :
     scene_(0),
     scene_(0),
     numLevels_(DEFAULT_OCTREE_LEVELS)
     numLevels_(DEFAULT_OCTREE_LEVELS)
 {
 {
+    // Resize threaded ray query intermediate result vector according to number of worker threads
+    rayQueryResults_.Resize(GetSubsystem<WorkQueue>()->GetNumThreads() + 1);
 }
 }
 
 
 Octree::~Octree()
 Octree::~Octree()
@@ -378,7 +424,55 @@ void Octree::GetDrawables(RayOctreeQuery& query) const
     PROFILE(Raycast);
     PROFILE(Raycast);
     
     
     query.result_.Clear();
     query.result_.Clear();
-    GetDrawablesInternal(query);
+    
+    // If no triangle-level testing, do not thread
+    if (query.level_ < RAY_TRIANGLE)
+        GetDrawablesInternal(query);
+    else
+    {
+        // Threaded ray query: first get the drawables
+        WorkQueue* queue = GetSubsystem<WorkQueue>();
+        
+        rayQuery_ = &query;
+        rayQueryDrawables_.Clear();
+        GetDrawablesOnlyInternal(query, rayQueryDrawables_);
+        
+        // Check that amount of drawables is large enough to justify threading
+        if (rayQueryDrawables_.Size() > RAYCASTS_PER_WORK_ITEM)
+        {
+            for (unsigned i = 0; i < rayQueryResults_.Size(); ++i)
+                rayQueryResults_[i].Clear();
+            
+            WorkItem item;
+            item.workFunction_ = RaycastDrawablesWork;
+            item.aux_ = const_cast<Octree*>(this);
+            
+            PODVector<Drawable*>::Iterator start = rayQueryDrawables_.Begin();
+            while (start != rayQueryDrawables_.End())
+            {
+                PODVector<Drawable*>::Iterator end = rayQueryDrawables_.End();
+                if (end - start > RAYCASTS_PER_WORK_ITEM)
+                    end = start + RAYCASTS_PER_WORK_ITEM;
+                
+                item.start_ = &(*start);
+                item.end_ = &(*end);
+                queue->AddWorkItem(item);
+                
+                start = end;
+            }
+            
+            // Merge per-thread results
+            queue->Complete();
+            for (unsigned i = 0; i < rayQueryResults_.Size(); ++i)
+                query.result_.Insert(query.result_.End(), rayQueryResults_[i].Begin(), rayQueryResults_[i].End());
+        }
+        else
+        {
+            for (PODVector<Drawable*>::Iterator i = rayQueryDrawables_.Begin(); i != rayQueryDrawables_.End(); ++i)
+                (*i)->ProcessRayQuery(query, query.result_);
+        }
+    }
+    
     Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults);
     Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults);
 }
 }
 
 

+ 11 - 2
Engine/Graphics/Octree.h

@@ -26,10 +26,9 @@
 #include "Drawable.h"
 #include "Drawable.h"
 #include "List.h"
 #include "List.h"
 #include "Mutex.h"
 #include "Mutex.h"
+#include "OctreeQuery.h"
 
 
 class Octree;
 class Octree;
-class OctreeQuery;
-class RayOctreeQuery;
 
 
 static const int NUM_OCTANTS = 8;
 static const int NUM_OCTANTS = 8;
 
 
@@ -97,6 +96,8 @@ protected:
     void GetDrawablesInternal(OctreeQuery& query, bool inside) const;
     void GetDrawablesInternal(OctreeQuery& query, bool inside) const;
     /// Return drawable objects by a ray query, called internally.
     /// Return drawable objects by a ray query, called internally.
     void GetDrawablesInternal(RayOctreeQuery& query) const;
     void GetDrawablesInternal(RayOctreeQuery& query) const;
+    /// Return drawable objects only for a threaded ray query, called internally.
+    void GetDrawablesOnlyInternal(RayOctreeQuery& query, PODVector<Drawable*>& drawables) const;
     /// Free child octants. If drawable objects still exist, move them to root.
     /// Free child octants. If drawable objects still exist, move them to root.
     void Release();
     void Release();
     
     
@@ -149,6 +150,8 @@ protected:
 /// %Octree component. Should be added only to the root scene node
 /// %Octree component. Should be added only to the root scene node
 class Octree : public Component, public Octant
 class Octree : public Component, public Octant
 {
 {
+    friend void RaycastDrawablesWork(const WorkItem* item, unsigned threadIndex);
+    
     OBJECT(Octree);
     OBJECT(Octree);
     
     
 public:
 public:
@@ -211,6 +214,12 @@ private:
     Mutex octreeMutex_;
     Mutex octreeMutex_;
     /// Unculled drawables.
     /// Unculled drawables.
     Vector<WeakPtr<Drawable> > unculledDrawables_;
     Vector<WeakPtr<Drawable> > unculledDrawables_;
+    /// Current threaded ray query.
+    mutable RayOctreeQuery* rayQuery_;
+    /// Drawable list for threaded ray query.
+    mutable PODVector<Drawable*> rayQueryDrawables_;
+    /// Threaded ray query intermediate results.
+    mutable Vector<PODVector<RayQueryResult> > rayQueryResults_;
     /// Subdivision level.
     /// Subdivision level.
     unsigned numLevels_;
     unsigned numLevels_;
 };
 };

+ 0 - 1
Engine/Graphics/Renderer.cpp

@@ -35,7 +35,6 @@
 #include "Material.h"
 #include "Material.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "Renderer.h"
 #include "Renderer.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"

+ 0 - 1
Engine/Graphics/View.cpp

@@ -31,7 +31,6 @@
 #include "Material.h"
 #include "Material.h"
 #include "OcclusionBuffer.h"
 #include "OcclusionBuffer.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "Renderer.h"
 #include "Renderer.h"
 #include "Profiler.h"
 #include "Profiler.h"
 #include "Scene.h"
 #include "Scene.h"

+ 0 - 1
Engine/Graphics/Zone.cpp

@@ -24,7 +24,6 @@
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Context.h"
 #include "Context.h"
 #include "Octree.h"
 #include "Octree.h"
-#include "OctreeQuery.h"
 #include "XMLElement.h"
 #include "XMLElement.h"
 #include "Zone.h"
 #include "Zone.h"