Browse Source

Threaded occlusion check for the main view.
Fixed worker thread work distribution in Octree & View.

Lasse Öörni 14 years ago
parent
commit
f3b5dae787
3 changed files with 95 additions and 47 deletions
  1. 3 6
      Engine/Graphics/Octree.cpp
  2. 84 38
      Engine/Graphics/View.cpp
  3. 8 3
      Engine/Graphics/View.h

+ 3 - 6
Engine/Graphics/Octree.cpp

@@ -468,11 +468,9 @@ void Octree::UpdateDrawables(const FrameInfo& frame)
     PODVector<Drawable*>::Iterator start = drawableUpdates_.Begin();
     PODVector<Drawable*>::Iterator start = drawableUpdates_.Begin();
     while (start != drawableUpdates_.End())
     while (start != drawableUpdates_.End())
     {
     {
-        PODVector<Drawable*>::Iterator end = start;
+        PODVector<Drawable*>::Iterator end = drawableUpdates_.End();
         if (end - start > DRAWABLES_PER_WORK_ITEM)
         if (end - start > DRAWABLES_PER_WORK_ITEM)
-            end += DRAWABLES_PER_WORK_ITEM;
-        else
-            end = drawableUpdates_.End();
+            end = start + DRAWABLES_PER_WORK_ITEM;
         
         
         item.start_ = &(*start);
         item.start_ = &(*start);
         item.end_ = &(*end);
         item.end_ = &(*end);
@@ -482,9 +480,8 @@ void Octree::UpdateDrawables(const FrameInfo& frame)
     }
     }
     
     
     queue->Complete();
     queue->Complete();
-    drawableUpdates_.Clear();
-    
     scene->EndThreadedUpdate();
     scene->EndThreadedUpdate();
+    drawableUpdates_.Clear();
     
     
     for (unsigned i = unculledDrawables_.Size() - 1; i < unculledDrawables_.Size(); --i)
     for (unsigned i = unculledDrawables_.Size() - 1; i < unculledDrawables_.Size(); --i)
     {
     {

+ 84 - 38
Engine/Graphics/View.cpp

@@ -57,6 +57,48 @@ static const Vector3 directions[] =
     Vector3(0.0f, 0.0f, -1.0f)
     Vector3(0.0f, 0.0f, -1.0f)
 };
 };
 
 
+static const int CHECK_DRAWABLES_PER_WORK_ITEM = 64;
+
+void CheckVisibilityWork(const WorkItem* item, unsigned threadIndex)
+{
+    View* view = reinterpret_cast<View*>(item->aux_);
+    Drawable** start = reinterpret_cast<Drawable**>(item->start_);
+    Drawable** end = reinterpret_cast<Drawable**>(item->end_);
+    Drawable** unculledStart = &view->tempDrawables_[0][view->unculledDrawableStart_];
+    OcclusionBuffer* buffer = view->occlusionBuffer_;
+    
+    while (start != end)
+    {
+        Drawable* drawable = *start;
+        bool useOcclusion = start < unculledStart;
+        unsigned char flags = drawable->GetDrawableFlags();
+        ++start;
+        
+        if (flags & DRAWABLE_ZONE)
+            continue;
+        
+        drawable->UpdateDistance(view->frame_);
+        
+        // If draw distance non-zero, check it
+        float maxDistance = drawable->GetDrawDistance();
+        if (maxDistance > 0.0f && drawable->GetDistance() > maxDistance)
+            continue;
+        
+        if (buffer && useOcclusion && !buffer->IsVisible(drawable->GetWorldBoundingBox()))
+            continue;
+        
+        drawable->MarkInView(view->frame_);
+        
+        // For geometries, clear lights and find new zone if necessary
+        if (flags & DRAWABLE_GEOMETRY)
+        {
+            drawable->ClearLights();
+            if (!drawable->GetZone() && !view->cameraZoneOverride_)
+                view->FindZone(drawable, threadIndex);
+        }
+    }
+}
+
 void ProcessLightWork(const WorkItem* item, unsigned threadIndex)
 void ProcessLightWork(const WorkItem* item, unsigned threadIndex)
 {
 {
     View* view = reinterpret_cast<View*>(item->aux_);
     View* view = reinterpret_cast<View*>(item->aux_);
@@ -122,8 +164,9 @@ View::View(Context* context) :
 {
 {
     frame_.camera_ = 0;
     frame_.camera_ = 0;
     
     
-    // Create an octree query vector for each thread
+    // Create octree query vectors for each thread
     tempDrawables_.Resize(GetSubsystem<WorkQueue>()->GetNumThreads() + 1);
     tempDrawables_.Resize(GetSubsystem<WorkQueue>()->GetNumThreads() + 1);
+    tempZones_.Resize(GetSubsystem<WorkQueue>()->GetNumThreads() + 1);
 }
 }
 
 
 View::~View()
 View::~View()
@@ -282,6 +325,7 @@ void View::Render()
     octree_ = 0;
     octree_ = 0;
     cameraZone_ = 0;
     cameraZone_ = 0;
     farClipZone_ = 0;
     farClipZone_ = 0;
+    occlusionBuffer_ = 0;
     frame_.camera_ = 0;
     frame_.camera_ = 0;
 }
 }
 
 
@@ -296,6 +340,10 @@ void View::GetDrawables()
     FrustumOctreeQuery query(tempDrawables, frustum_, DRAWABLE_GEOMETRY | DRAWABLE_LIGHT | DRAWABLE_ZONE);
     FrustumOctreeQuery query(tempDrawables, frustum_, DRAWABLE_GEOMETRY | DRAWABLE_LIGHT | DRAWABLE_ZONE);
     octree_->GetDrawables(query);
     octree_->GetDrawables(query);
     
     
+    // Add unculled geometries & lights
+    unculledDrawableStart_ = tempDrawables.Size();
+    octree_->GetUnculledDrawables(tempDrawables, DRAWABLE_GEOMETRY | DRAWABLE_LIGHT);
+    
     // Get zones and occluders first
     // Get zones and occluders first
     highestZonePriority_ = M_MIN_INT;
     highestZonePriority_ = M_MIN_INT;
     int bestPriority = M_MIN_INT;
     int bestPriority = M_MIN_INT;
@@ -308,7 +356,7 @@ void View::GetDrawables()
     for (PODVector<Drawable*>::ConstIterator i = tempDrawables.Begin(); i != tempDrawables.End(); ++i)
     for (PODVector<Drawable*>::ConstIterator i = tempDrawables.Begin(); i != tempDrawables.End(); ++i)
     {
     {
         Drawable* drawable = *i;
         Drawable* drawable = *i;
-        unsigned flags = drawable->GetDrawableFlags();
+        unsigned char flags = drawable->GetDrawableFlags();
         
         
         if (flags & DRAWABLE_ZONE)
         if (flags & DRAWABLE_ZONE)
         {
         {
@@ -347,8 +395,8 @@ void View::GetDrawables()
     if (farClipZone_ == defaultZone)
     if (farClipZone_ == defaultZone)
         farClipZone_ = cameraZone_;
         farClipZone_ = cameraZone_;
     
     
-    // If occlusion in use, get & render the occluders, then build the depth buffer hierarchy
-    OcclusionBuffer* buffer = 0;
+    // If occlusion in use, get & render the occluders
+    occlusionBuffer_ = 0;
     if (maxOccluderTriangles_ > 0)
     if (maxOccluderTriangles_ > 0)
     {
     {
         UpdateOccluders(occluders_, camera_);
         UpdateOccluders(occluders_, camera_);
@@ -356,14 +404,33 @@ void View::GetDrawables()
         {
         {
             PROFILE(DrawOcclusion);
             PROFILE(DrawOcclusion);
             
             
-            buffer = renderer_->GetOcclusionBuffer(camera_);
-            DrawOccluders(buffer, occluders_);
+            occlusionBuffer_ = renderer_->GetOcclusionBuffer(camera_);
+            DrawOccluders(occlusionBuffer_, occluders_);
         }
         }
     }
     }
     
     
-    // Add unculled geometries & lights
-    unsigned unculledDrawablesStart = tempDrawables.Size();
-    octree_->GetUnculledDrawables(tempDrawables, DRAWABLE_GEOMETRY | DRAWABLE_LIGHT);
+    // Check visibility and find zones for moved drawables in worker threads
+    {
+        WorkItem item;
+        item.workFunction_ = CheckVisibilityWork;
+        item.aux_ = this;
+        
+        PODVector<Drawable*>::Iterator start = tempDrawables.Begin();
+        while (start != tempDrawables.End())
+        {
+            PODVector<Drawable*>::Iterator end = tempDrawables.End();
+            if (end - start > CHECK_DRAWABLES_PER_WORK_ITEM)
+                end = start + CHECK_DRAWABLES_PER_WORK_ITEM;
+            
+            item.start_ = &(*start);
+            item.end_ = &(*end);
+            queue->AddWorkItem(item);
+            
+            start = end;
+        }
+        
+        queue->Complete();
+    }
     
     
     // Sort into geometries & lights, and build visible scene bounding boxes in world and view space
     // Sort into geometries & lights, and build visible scene bounding boxes in world and view space
     sceneBox_.min_ = sceneBox_.max_ = Vector3::ZERO;
     sceneBox_.min_ = sceneBox_.max_ = Vector3::ZERO;
@@ -372,34 +439,15 @@ void View::GetDrawables()
     sceneViewBox_.defined_ = false;
     sceneViewBox_.defined_ = false;
     Matrix3x4 view(camera_->GetInverseWorldTransform());
     Matrix3x4 view(camera_->GetInverseWorldTransform());
     
     
-    // Now go through the drawable list again for geometries and lights
     for (unsigned i = 0; i < tempDrawables.Size(); ++i)
     for (unsigned i = 0; i < tempDrawables.Size(); ++i)
     {
     {
         Drawable* drawable = tempDrawables[i];
         Drawable* drawable = tempDrawables[i];
-        unsigned flags = drawable->GetDrawableFlags();
-        if (!(flags & (DRAWABLE_GEOMETRY | DRAWABLE_LIGHT)))
-            continue;
-        
-        drawable->UpdateDistance(frame_);
-        
-        // If draw distance non-zero, check it
-        float maxDistance = drawable->GetDrawDistance();
-        if (maxDistance > 0.0f && drawable->GetDistance() > maxDistance)
-            continue;
-        
-        /// \todo Should test the drawables' octants first, or use threading for the visibility tests
-        if (buffer && i < unculledDrawablesStart && !buffer->IsVisible(drawable->GetWorldBoundingBox()))
+        unsigned char flags = drawable->GetDrawableFlags();
+        if (flags & DRAWABLE_ZONE || !drawable->IsInView(frame_))
             continue;
             continue;
         
         
         if (flags & DRAWABLE_GEOMETRY)
         if (flags & DRAWABLE_GEOMETRY)
         {
         {
-            // Find new zone for the drawable if necessary
-            if (!drawable->GetZone() && !cameraZoneOverride_)
-                FindZone(drawable);
-            
-            drawable->ClearLights();
-            drawable->MarkInView(frame_);
-            
             // Expand the scene bounding boxes. However, do not take "infinite" objects such as the skybox into account,
             // Expand the scene bounding boxes. However, do not take "infinite" objects such as the skybox into account,
             // as the bounding boxes are also used for shadow focusing
             // as the bounding boxes are also used for shadow focusing
             const BoundingBox& geomBox = drawable->GetWorldBoundingBox();
             const BoundingBox& geomBox = drawable->GetWorldBoundingBox();
@@ -422,7 +470,6 @@ void View::GetDrawables()
         else if (flags & DRAWABLE_LIGHT)
         else if (flags & DRAWABLE_LIGHT)
         {
         {
             Light* light = static_cast<Light*>(drawable);
             Light* light = static_cast<Light*>(drawable);
-            light->MarkInView(frame_);
             lights_.Push(light);
             lights_.Push(light);
         }
         }
     }
     }
@@ -721,11 +768,9 @@ void View::UpdateGeometries()
             PODVector<Drawable*>::Iterator start = threadedGeometries_.Begin();
             PODVector<Drawable*>::Iterator start = threadedGeometries_.Begin();
             while (start != threadedGeometries_.End())
             while (start != threadedGeometries_.End())
             {
             {
-                PODVector<Drawable*>::Iterator end = start;
+                PODVector<Drawable*>::Iterator end = threadedGeometries_.End();
                 if (end - start > DRAWABLES_PER_WORK_ITEM)
                 if (end - start > DRAWABLES_PER_WORK_ITEM)
-                    end += DRAWABLES_PER_WORK_ITEM;
-                else
-                    end = threadedGeometries_.End();
+                    end = start + DRAWABLES_PER_WORK_ITEM;
                 
                 
                 item.start_ = &(*start);
                 item.start_ = &(*start);
                 item.end_ = &(*end);
                 item.end_ = &(*end);
@@ -1591,7 +1636,7 @@ void View::QuantizeDirLightShadowCamera(Camera* shadowCamera, Light* light, cons
     }
     }
 }
 }
 
 
-void View::FindZone(Drawable* drawable)
+void View::FindZone(Drawable* drawable, unsigned threadIndex)
 {
 {
     Vector3 center = drawable->GetWorldBoundingBox().Center();
     Vector3 center = drawable->GetWorldBoundingBox().Center();
     int bestPriority = M_MIN_INT;
     int bestPriority = M_MIN_INT;
@@ -1620,11 +1665,12 @@ void View::FindZone(Drawable* drawable)
     }
     }
     else
     else
     {
     {
-        PointOctreeQuery query(reinterpret_cast<PODVector<Drawable*>&>(tempZones_), center, DRAWABLE_ZONE);
+        PODVector<Zone*>& tempZones = tempZones_[threadIndex];
+        PointOctreeQuery query(reinterpret_cast<PODVector<Drawable*>&>(tempZones), center, DRAWABLE_ZONE);
         octree_->GetDrawables(query);
         octree_->GetDrawables(query);
         
         
         bestPriority = M_MIN_INT;
         bestPriority = M_MIN_INT;
-        for (PODVector<Zone*>::Iterator i = tempZones_.Begin(); i != tempZones_.End(); ++i)
+        for (PODVector<Zone*>::Iterator i = tempZones.Begin(); i != tempZones.End(); ++i)
         {
         {
             int priority = (*i)->GetPriority();
             int priority = (*i)->GetPriority();
             if ((*i)->IsInside(center) && (drawable->GetZoneMask() & (*i)->GetZoneMask()) && priority > bestPriority)
             if ((*i)->IsInside(center) && (drawable->GetZoneMask() & (*i)->GetZoneMask()) && priority > bestPriority)

+ 8 - 3
Engine/Graphics/View.h

@@ -79,6 +79,7 @@ struct LightQueryResult
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
 /// 3D rendering view. Includes the main view(s) and any auxiliary views, but not shadow cameras.
 class View : public Object
 class View : public Object
 {
 {
+    friend void CheckVisibilityWork(const WorkItem* item, unsigned threadIndex);
     friend void ProcessLightWork(const WorkItem* item, unsigned threadIndex);
     friend void ProcessLightWork(const WorkItem* item, unsigned threadIndex);
     
     
     OBJECT(View);
     OBJECT(View);
@@ -153,7 +154,7 @@ private:
     /// Split directional or point light for shadow rendering.
     /// Split directional or point light for shadow rendering.
     unsigned SplitLight(Light* light);
     unsigned SplitLight(Light* light);
     /// Find and set a new zone for a drawable when it has moved.
     /// Find and set a new zone for a drawable when it has moved.
-    void FindZone(Drawable* drawable);
+    void FindZone(Drawable* drawable, unsigned threadIndex);
     /// Return the drawable's zone, or camera zone if it has override mode enabled.
     /// Return the drawable's zone, or camera zone if it has override mode enabled.
     Zone* GetZone(Drawable* drawable);
     Zone* GetZone(Drawable* drawable);
     /// Return the drawable's light mask, considering also its zone.
     /// Return the drawable's light mask, considering also its zone.
@@ -185,6 +186,8 @@ private:
     Zone* cameraZone_;
     Zone* cameraZone_;
     /// Zone at far clip plane.
     /// Zone at far clip plane.
     Zone* farClipZone_;
     Zone* farClipZone_;
+    /// Occlusion buffer for the main camera.
+    OcclusionBuffer* occlusionBuffer_;
     /// Color buffer to use.
     /// Color buffer to use.
     RenderSurface* renderTarget_;
     RenderSurface* renderTarget_;
     /// Depth buffer to use.
     /// Depth buffer to use.
@@ -203,6 +206,8 @@ private:
     int maxOccluderTriangles_;
     int maxOccluderTriangles_;
     /// Highest zone priority currently visible.
     /// Highest zone priority currently visible.
     int highestZonePriority_;
     int highestZonePriority_;
+    /// Start index of unculled drawables. These will not be tested for occlusion.
+    unsigned unculledDrawableStart_;
     /// Information of the frame being rendered.
     /// Information of the frame being rendered.
     FrameInfo frame_;
     FrameInfo frame_;
     /// Camera frustum.
     /// Camera frustum.
@@ -215,8 +220,8 @@ private:
     Polyhedron frustumVolume_;
     Polyhedron frustumVolume_;
     /// Per-thread octree query results.
     /// Per-thread octree query results.
     Vector<PODVector<Drawable*> > tempDrawables_;
     Vector<PODVector<Drawable*> > tempDrawables_;
-    /// Octree zone query result.
-    PODVector<Zone*> tempZones_;
+    /// Per-thread octree zone query results.
+    Vector<PODVector<Zone*> > tempZones_;
     /// Visible zones.
     /// Visible zones.
     PODVector<Zone*> zones_;
     PODVector<Zone*> zones_;
     /// Visible geometry objects.
     /// Visible geometry objects.