Browse Source

Use multi thread check Drawable2D visiblity.

aster2013 11 years ago
parent
commit
0cfe56310a
2 changed files with 58 additions and 24 deletions
  1. 56 22
      Source/Engine/Urho2D/DrawableProxy2D.cpp
  2. 2 2
      Source/Engine/Urho2D/DrawableProxy2D.h

+ 56 - 22
Source/Engine/Urho2D/DrawableProxy2D.cpp

@@ -35,6 +35,7 @@
 #include "Scene.h"
 #include "Scene.h"
 #include "VertexBuffer.h"
 #include "VertexBuffer.h"
 #include "Sort.h"
 #include "Sort.h"
+#include "WorkQueue.h"
 
 
 #include "DebugNew.h"
 #include "DebugNew.h"
 
 
@@ -183,6 +184,15 @@ void DrawableProxy2D::RemoveDrawable(Drawable2D* drawable)
     orderDirty_ = true;
     orderDirty_ = true;
 }
 }
 
 
+bool DrawableProxy2D::CheckVisibility(Drawable2D* drawable) const
+{
+    const BoundingBox& box = drawable->GetWorldBoundingBox();
+    if (frustum_)
+        return frustum_->IsInsideFast(box) != OUTSIDE;
+
+    return frustumBoundingBox_.IsInsideFast(box) != OUTSIDE;
+}
+
 void DrawableProxy2D::OnWorldBoundingBoxUpdate()
 void DrawableProxy2D::OnWorldBoundingBoxUpdate()
 {
 {
     // Set a large dummy bounding box to ensure the proxy is rendered
     // Set a large dummy bounding box to ensure the proxy is rendered
@@ -190,6 +200,22 @@ void DrawableProxy2D::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_;
     worldBoundingBox_ = boundingBox_;
 }
 }
 
 
+void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
+{
+    DrawableProxy2D* proxy = reinterpret_cast<DrawableProxy2D*>(item->aux_);
+    Drawable2D** start = reinterpret_cast<Drawable2D**>(item->start_);
+    Drawable2D** end = reinterpret_cast<Drawable2D**>(item->end_);
+
+    while (start != end)
+    {
+        Drawable2D* drawable = *start++;
+        if (proxy->CheckVisibility(drawable) && drawable->GetUsedMaterial() && drawable->GetVertices().Size())
+            drawable->SetVisibility(true);
+        else
+            drawable->SetVisibility(false);
+    }
+}
+
 void DrawableProxy2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData)
 void DrawableProxy2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData)
 {
 {
     using namespace BeginViewUpdate;
     using namespace BeginViewUpdate;
@@ -206,8 +232,6 @@ void DrawableProxy2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& ev
         orderDirty_ = false;
         orderDirty_ = false;
     }
     }
 
 
-    vertexCount_ = 0;
-
     Camera* camera = static_cast<Camera*>(eventData[P_CAMERA].GetPtr());
     Camera* camera = static_cast<Camera*>(eventData[P_CAMERA].GetPtr());
     frustum_ = &camera->GetFrustum();
     frustum_ = &camera->GetFrustum();
     if (camera->IsOrthographic() && camera->GetNode()->GetWorldDirection() == Vector3::FORWARD)
     if (camera->IsOrthographic() && camera->GetNode()->GetWorldDirection() == Vector3::FORWARD)
@@ -217,22 +241,41 @@ void DrawableProxy2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& ev
         frustum_ = 0;
         frustum_ = 0;
     }
     }
 
 
-    for (unsigned i = 0; i < drawables_.Size(); ++i)
     {
     {
-        drawables_[i]->SetVisibility(false);
-
-        if (CheckVisibility(drawables_[i]) && drawables_[i]->GetUsedMaterial())
+        PROFILE(CheckDrawableVisibility);
+
+        WorkQueue* queue = GetSubsystem<WorkQueue>();
+        int numWorkItems = queue->GetNumThreads() + 1; // Worker threads + main thread
+        int drawablesPerItem = drawables_.Size() / numWorkItems;
+        
+        PODVector<Drawable2D*>::Iterator start = drawables_.Begin();
+        for (int i = 0; i < numWorkItems; ++i)
         {
         {
-            // Delay call Drawable2D::GetVertices
-            const Vector<Vertex2D>& vertices = drawables_[i]->GetVertices();
-            if (!vertices.Empty())
-            {
-                drawables_[i]->SetVisibility(true);
-                vertexCount_ += vertices.Size();
-            }
+            SharedPtr<WorkItem> item = queue->GetFreeItem();
+            item->priority_ = M_MAX_UNSIGNED;
+            item->workFunction_ = CheckDrawableVisibility;
+            item->aux_ = this;
+
+            PODVector<Drawable2D*>::Iterator end = drawables_.End();
+            if (i < numWorkItems - 1 && end - start > drawablesPerItem)
+                end = start + drawablesPerItem;
+            
+            item->start_ = &(*start);
+            item->end_ = &(*end);
+            queue->AddWorkItem(item);
+            
+            start = end;
         }
         }
+
+        queue->Complete(M_MAX_UNSIGNED);
     }
     }
 
 
+    vertexCount_ = 0;
+    for (unsigned i = 0; i < drawables_.Size(); ++i)
+    {
+        if (drawables_[i]->GetVisibility())
+            vertexCount_ += drawables_[i]->GetVertices().Size();
+    }
     indexCount_ = vertexCount_ / 4 * 6;
     indexCount_ = vertexCount_ / 4 * 6;
 
 
     // Go through the drawables to form geometries & batches, but upload the actual vertex data later
     // Go through the drawables to form geometries & batches, but upload the actual vertex data later
@@ -285,15 +328,6 @@ void DrawableProxy2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& ev
     }
     }
 }
 }
 
 
-bool DrawableProxy2D::CheckVisibility(Drawable2D* drawable) const
-{
-    const BoundingBox& box = drawable->GetWorldBoundingBox();
-    if (frustum_)
-        return frustum_->IsInsideFast(box) != OUTSIDE;
-
-    return frustumBoundingBox_.IsInsideFast(box) != OUTSIDE;
-}
-
 void DrawableProxy2D::AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount)
 void DrawableProxy2D::AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount)
 {
 {
     if (!material || indexCount == 0 || vertexCount == 0)
     if (!material || indexCount == 0 || vertexCount == 0)

+ 2 - 2
Source/Engine/Urho2D/DrawableProxy2D.h

@@ -57,14 +57,14 @@ public:
     void RemoveDrawable(Drawable2D* drawable);
     void RemoveDrawable(Drawable2D* drawable);
     /// Mark order dirty.
     /// Mark order dirty.
     void MarkOrderDirty() { orderDirty_ = true; }
     void MarkOrderDirty() { orderDirty_ = true; }
+    /// Check visibility.
+    bool CheckVisibility(Drawable2D* drawable) const;
 
 
 private:
 private:
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.
     virtual void OnWorldBoundingBoxUpdate();
     virtual void OnWorldBoundingBoxUpdate();
     /// Handle view update begin event. Determine Drawable2D's and their batches here.
     /// Handle view update begin event. Determine Drawable2D's and their batches here.
     void HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData);
     void HandleBeginViewUpdate(StringHash eventType, VariantMap& eventData);
-    /// Check visibility.
-    bool CheckVisibility(Drawable2D* drawable) const;
     /// Add batch.
     /// Add batch.
     void AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount);
     void AddBatch(Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount);