Browse Source

Improved front-to-back batch sorting: consider both state & distance.

Lasse Öörni 13 years ago
parent
commit
a2ee32c88f
2 changed files with 41 additions and 20 deletions
  1. 40 17
      Engine/Graphics/Batch.cpp
  2. 1 3
      Engine/Graphics/View.cpp

+ 40 - 17
Engine/Graphics/Batch.cpp

@@ -61,12 +61,34 @@ inline bool CompareInstancesFrontToBack(const InstanceData& lhs, const InstanceD
     return lhs.distance_ < rhs.distance_;
     return lhs.distance_ < rhs.distance_;
 }
 }
 
 
-inline bool CompareBatchGroupsFrontToBack(BatchGroup* lhs, BatchGroup* rhs)
+static void SortFrontToBack2Pass(PODVector<Batch*>& batches)
 {
 {
-    if (lhs->sortKey_ == rhs->sortKey_)
-        return lhs->distance_ < rhs->distance_;
-    else
-        return lhs->sortKey_ > rhs->sortKey_;
+    // First sort with state having priority
+    Sort(batches.Begin(), batches.End(), CompareBatchesFrontToBack);
+    
+    // Then rewrite distances so that different states will be ordered front to back, and sort again
+    float lastDistance;
+    unsigned long long lastSortKey;
+    for (PODVector<Batch*>::Iterator i = batches.Begin(); i != batches.End(); ++i)
+    {
+        Batch* batch = *i;
+        
+        if (i == batches.Begin() || batch->sortKey_ != lastSortKey)
+        {
+            lastSortKey = batch->sortKey_;
+            lastDistance = batch->distance_;
+        }
+        else
+        {
+            lastDistance *= 1.000001f;
+            batch->distance_ = lastDistance;
+        }
+        
+        // Leave only the base & alphamask bits to the sort key
+        batch->sortKey_ &= 0xc000000000000000ULL;
+    }
+    
+    Sort(batches.Begin(), batches.End(), CompareBatchesFrontToBack);
 }
 }
 
 
 void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split, Renderer* renderer, const Vector3& translation)
 void CalculateShadowMatrix(Matrix4& dest, LightBatchQueue* queue, unsigned split, Renderer* renderer, const Vector3& translation)
@@ -155,15 +177,17 @@ void CalculateSpotMatrix(Matrix4& dest, Light* light, const Vector3& translation
 
 
 void Batch::CalculateSortKey()
 void Batch::CalculateSortKey()
 {
 {
-    unsigned lightQueue = (*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0x3fff;
-    unsigned pass = (*((unsigned*)&pass_) / sizeof(Pass)) & 0xffff;
-    unsigned material = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
-    unsigned geometry = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
+    unsigned shaders = ((*((unsigned*)&vertexShader_) / sizeof(ShaderVariation)) + (*((unsigned*)&pixelShader_) / sizeof(ShaderVariation))) & 0x3fff;
     if (isBase_)
     if (isBase_)
-        lightQueue |= 0x8000;
+        shaders |= 0x8000;
     if (pass_ && !pass_->GetAlphaMask())
     if (pass_ && !pass_->GetAlphaMask())
-        lightQueue |= 0x4000;
-    sortKey_ = (((unsigned long long)lightQueue) << 48) | (((unsigned long long)pass) << 32) |
+        shaders |= 0x4000;
+    
+    unsigned lightQueue = (*((unsigned*)&lightQueue_) / sizeof(LightBatchQueue)) & 0xffff;
+    unsigned material = (*((unsigned*)&material_) / sizeof(Material)) & 0xffff;
+    unsigned geometry = (*((unsigned*)&geometry_) / sizeof(Geometry)) & 0xffff;
+    
+    sortKey_ = (((unsigned long long)shaders) << 48) | (((unsigned long long)lightQueue) << 32) |
         (((unsigned long long)material) << 16) | geometry;
         (((unsigned long long)material) << 16) | geometry;
 }
 }
 
 
@@ -745,8 +769,8 @@ void BatchQueue::SortFrontToBack()
             sortedBatches_.Push(&batches_[i]);
             sortedBatches_.Push(&batches_[i]);
     }
     }
     
     
-    Sort(sortedBaseBatches_.Begin(), sortedBaseBatches_.End(), CompareBatchesFrontToBack);
-    Sort(sortedBatches_.Begin(), sortedBatches_.End(), CompareBatchesFrontToBack);
+    SortFrontToBack2Pass(sortedBaseBatches_);
+    SortFrontToBack2Pass(sortedBatches_);
     
     
     // Sort each group front to back
     // Sort each group front to back
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = baseBatchGroups_.Begin(); i != baseBatchGroups_.End(); ++i)
@@ -783,7 +807,6 @@ void BatchQueue::SortFrontToBack()
         }
         }
     }
     }
     
     
-    // Now sort batch groups by the distance of the first batch
     sortedBaseBatchGroups_.Resize(baseBatchGroups_.Size());
     sortedBaseBatchGroups_.Resize(baseBatchGroups_.Size());
     sortedBatchGroups_.Resize(batchGroups_.Size());
     sortedBatchGroups_.Resize(batchGroups_.Size());
     
     
@@ -794,8 +817,8 @@ void BatchQueue::SortFrontToBack()
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
     for (HashMap<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
         sortedBatchGroups_[index++] = &i->second_;
         sortedBatchGroups_[index++] = &i->second_;
     
     
-    Sort(sortedBaseBatchGroups_.Begin(), sortedBaseBatchGroups_.End(), CompareBatchGroupsFrontToBack);
-    Sort(sortedBatchGroups_.Begin(), sortedBatchGroups_.End(), CompareBatchGroupsFrontToBack);
+    SortFrontToBack2Pass(reinterpret_cast<PODVector<Batch*>& >(sortedBaseBatchGroups_));
+    SortFrontToBack2Pass(reinterpret_cast<PODVector<Batch*>& >(sortedBatchGroups_));
 }
 }
 
 
 void BatchQueue::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)
 void BatchQueue::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)

+ 1 - 3
Engine/Graphics/View.cpp

@@ -1219,7 +1219,7 @@ void View::RenderBatchesForward()
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
     
     
     #ifndef GL_ES_VERSION_2_0
     #ifndef GL_ES_VERSION_2_0
-    // At this point clear the parts of viewport not occupied by opaque geometry with fog color
+    // At this point clear the parts of viewport not occupied by opaque geometry with fog color.
     // On OpenGL ES an ordinary color clear has been performed beforehand instead
     // On OpenGL ES an ordinary color clear has been performed beforehand instead
     graphics_->SetBlendMode(BLEND_REPLACE);
     graphics_->SetBlendMode(BLEND_REPLACE);
     graphics_->SetColorWrite(true);
     graphics_->SetColorWrite(true);
@@ -2367,9 +2367,7 @@ void View::AddBatchToQueue(BatchQueue& batchQueue, Batch& batch, Technique* tech
             // Create a new group based on the batch
             // Create a new group based on the batch
             renderer_->SetBatchShaders(batch, tech, allowShadows);
             renderer_->SetBatchShaders(batch, tech, allowShadows);
             BatchGroup newGroup(batch);
             BatchGroup newGroup(batch);
-            // Retain only the base and alpha mask bits in the sort key for better distance sorting
             newGroup.CalculateSortKey();
             newGroup.CalculateSortKey();
-            newGroup.sortKey_ &= 0xc000000000000000ULL;
             newGroup.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
             newGroup.instances_.Push(InstanceData(batch.worldTransform_, batch.distance_));
             groups->Insert(MakePair(key, newGroup));
             groups->Insert(MakePair(key, newGroup));
         }
         }