Kaynağa Gözat

Added configurable instancing group minimum size and maximum triangles per instanced object.

Lasse Öörni 14 yıl önce
ebeveyn
işleme
fc3896fe02

+ 2 - 9
Docs/ScriptAPI.dox

@@ -1989,14 +1989,6 @@ Properties:<br>
 - int[]@ multiSampleLevels (readonly)
 - int[]@ multiSampleLevels (readonly)
 
 
 
 
-EdgeFilterParameters
-
-Properties:<br>
-- float radius
-- float threshold
-- float strength
-
-
 Renderer
 Renderer
 
 
 Methods:<br>
 Methods:<br>
@@ -2018,7 +2010,8 @@ Properties:<br>
 - bool shadowMapHiresDepth
 - bool shadowMapHiresDepth
 - bool reuseShadowMaps
 - bool reuseShadowMaps
 - bool dynamicInstancing
 - bool dynamicInstancing
-- EdgeFilterParameters& edgeFilter
+- int minInstanceGroupSize
+- int maxInstanceTriangles
 - int maxOccluderTriangles
 - int maxOccluderTriangles
 - int occlusionBufferSize
 - int occlusionBufferSize
 - float occluderSizeThreshold
 - float occluderSizeThreshold

+ 4 - 0
Engine/Engine/GraphicsAPI.cpp

@@ -764,6 +764,10 @@ static void RegisterRenderer(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Renderer", "bool get_reuseShadowMaps() const", asMETHOD(Renderer, GetReuseShadowMaps), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool get_reuseShadowMaps() const", asMETHOD(Renderer, GetReuseShadowMaps), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_dynamicInstancing(bool)", asMETHOD(Renderer, SetDynamicInstancing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_dynamicInstancing(bool)", asMETHOD(Renderer, SetDynamicInstancing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool get_dynamicInstancing() const", asMETHOD(Renderer, GetDynamicInstancing), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "bool get_dynamicInstancing() const", asMETHOD(Renderer, GetDynamicInstancing), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Renderer", "void set_minInstanceGroupSize(int)", asMETHOD(Renderer, SetMinInstanceGroupSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Renderer", "int get_minInstanceGroupSize() const", asMETHOD(Renderer, GetMinInstanceGroupSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Renderer", "void set_maxInstanceTriangles(int)", asMETHOD(Renderer, SetMaxInstanceTriangles), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Renderer", "int get_maxInstanceTriangles() const", asMETHOD(Renderer, GetMaxInstanceTriangles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_maxOccluderTriangles(int)", asMETHOD(Renderer, SetMaxOccluderTriangles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_maxOccluderTriangles(int)", asMETHOD(Renderer, SetMaxOccluderTriangles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "int get_maxOccluderTriangles() const", asMETHOD(Renderer, GetMaxOccluderTriangles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "int get_maxOccluderTriangles() const", asMETHOD(Renderer, GetMaxOccluderTriangles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_occlusionBufferSize(int)", asMETHOD(Renderer, SetOcclusionBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Renderer", "void set_occlusionBufferSize(int)", asMETHOD(Renderer, SetOcclusionBufferSize), asCALL_THISCALL);

+ 17 - 9
Engine/Graphics/Batch.cpp

@@ -354,10 +354,12 @@ void Batch::Draw(Graphics* graphics, const HashMap<StringHash, Vector4>& shaderP
     geometry_->Draw(graphics);
     geometry_->Draw(graphics);
 }
 }
 
 
-void BatchGroup::SetTransforms(void* lockedData, unsigned& freeIndex)
+void BatchGroup::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)
 {
 {
     // Do not use up buffer space if not going to draw as instanced
     // Do not use up buffer space if not going to draw as instanced
-    if (instances_.Size() < MIN_INSTANCES)
+    unsigned minGroupSize = renderer->GetMinInstanceGroupSize();
+    unsigned maxIndexCount = renderer->GetMaxInstanceTriangles() * 3;
+    if (instances_.Size() < minGroupSize || geometry_->GetIndexCount() > maxIndexCount)
         return;
         return;
     
     
     startIndex_ = freeIndex;
     startIndex_ = freeIndex;
@@ -386,8 +388,12 @@ void BatchGroup::Draw(Graphics* graphics, VertexBuffer* instanceBuffer, const Ha
     batch.light_ = light_;
     batch.light_ = light_;
     batch.vertexShaderIndex_ = vertexShaderIndex_;
     batch.vertexShaderIndex_ = vertexShaderIndex_;
     
     
+    Renderer* renderer = graphics->GetSubsystem<Renderer>();
+    unsigned minGroupSize = renderer->GetMinInstanceGroupSize();
+    unsigned maxIndexCount = renderer->GetMaxInstanceTriangles() * 3;
+    
     // Draw as individual instances if below minimum size, or if instancing not supported
     // Draw as individual instances if below minimum size, or if instancing not supported
-    if (instances_.Size() < MIN_INSTANCES || !instanceBuffer)
+    if (!instanceBuffer || instances_.Size() < minGroupSize || geometry_->GetIndexCount() > maxIndexCount)
     {
     {
         batch.Prepare(graphics, shaderParameters, false);
         batch.Prepare(graphics, shaderParameters, false);
         
         
@@ -542,30 +548,32 @@ void BatchQueue::SortFrontToBack()
         Sort(i->second_.instances_.Begin(), i->second_.instances_.End(), CompareInstancesFrontToBack);
         Sort(i->second_.instances_.Begin(), i->second_.instances_.End(), CompareInstancesFrontToBack);
 }
 }
 
 
-void BatchQueue::SetTransforms(void* lockedData, unsigned& freeIndex)
+void BatchQueue::SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex)
 {
 {
     for (Map<BatchGroupKey, BatchGroup>::Iterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
     for (Map<BatchGroupKey, BatchGroup>::Iterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
-        i->second_.SetTransforms(lockedData, freeIndex);
+        i->second_.SetTransforms(renderer, lockedData, freeIndex);
     for (Map<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
     for (Map<BatchGroupKey, BatchGroup>::Iterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
-        i->second_.SetTransforms(lockedData, freeIndex);
+        i->second_.SetTransforms(renderer, lockedData, freeIndex);
 }
 }
 
 
-unsigned BatchQueue::GetNumInstances() const
+unsigned BatchQueue::GetNumInstances(Renderer* renderer) const
 {
 {
     unsigned total = 0;
     unsigned total = 0;
+    unsigned minGroupSize = renderer->GetMinInstanceGroupSize();
+    unsigned maxIndexCount = renderer->GetMaxInstanceTriangles() * 3;
     
     
     // This is for the purpose of calculating how much space is needed in the instancing buffer. Do not add instance counts
     // This is for the purpose of calculating how much space is needed in the instancing buffer. Do not add instance counts
     // that are below the minimum threshold for instancing
     // that are below the minimum threshold for instancing
     for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
     for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = priorityBatchGroups_.Begin(); i != priorityBatchGroups_.End(); ++i)
     {
     {
         unsigned instances = i->second_.instances_.Size();
         unsigned instances = i->second_.instances_.Size();
-        if (instances >= MIN_INSTANCES)
+        if (instances >= minGroupSize && i->second_.geometry_->GetIndexCount() <= maxIndexCount)
             total += instances;
             total += instances;
     }
     }
     for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
     for (Map<BatchGroupKey, BatchGroup>::ConstIterator i = batchGroups_.Begin(); i != batchGroups_.End(); ++i)
     {
     {
         unsigned instances = i->second_.instances_.Size();
         unsigned instances = i->second_.instances_.Size();
-        if (instances >= MIN_INSTANCES)
+        if (instances >= minGroupSize && i->second_.geometry_->GetIndexCount() <= maxIndexCount)
             total += instances;
             total += instances;
     }
     }
     
     

+ 5 - 4
Engine/Graphics/Batch.h

@@ -36,8 +36,9 @@ class Geometry;
 class Graphics;
 class Graphics;
 class Light;
 class Light;
 class Material;
 class Material;
-class Pass;
 class Matrix3x4;
 class Matrix3x4;
+class Pass;
+class Renderer;
 class ShaderVariation;
 class ShaderVariation;
 class VertexBuffer;
 class VertexBuffer;
 
 
@@ -132,7 +133,7 @@ struct BatchGroup
     }
     }
     
     
     /// Pre-set the instance transforms. Buffer must be big enough to hold all transforms.
     /// Pre-set the instance transforms. Buffer must be big enough to hold all transforms.
-    void SetTransforms(void* lockedData, unsigned& freeIndex);
+    void SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex);
     /// Prepare and draw.
     /// Prepare and draw.
     void Draw(Graphics* graphics, VertexBuffer* instanceBuffer, const HashMap<StringHash, Vector4>& shaderParameters) const;
     void Draw(Graphics* graphics, VertexBuffer* instanceBuffer, const HashMap<StringHash, Vector4>& shaderParameters) const;
     
     
@@ -227,10 +228,10 @@ public:
     /// Sort instanced and non-instanced draw calls front to back.
     /// Sort instanced and non-instanced draw calls front to back.
     void SortFrontToBack();
     void SortFrontToBack();
     /// Pre-set instance transforms of all groups. The vertex buffer must be big enough to hold all transforms.
     /// Pre-set instance transforms of all groups. The vertex buffer must be big enough to hold all transforms.
-    void SetTransforms(void* lockedData, unsigned& freeIndex);
+    void SetTransforms(Renderer* renderer, void* lockedData, unsigned& freeIndex);
     
     
     /// Return the combined amount of instances.
     /// Return the combined amount of instances.
-    unsigned GetNumInstances() const;
+    unsigned GetNumInstances(Renderer* renderer) const;
     /// Return whether the batch group is empty.
     /// Return whether the batch group is empty.
     bool IsEmpty() const { return batches_.Empty() && priorityBatchGroups_.Empty() && batchGroups_.Empty(); }
     bool IsEmpty() const { return batches_.Empty() && priorityBatchGroups_.Empty() && batchGroups_.Empty(); }
     /// Unsorted non-instanced draw calls.
     /// Unsorted non-instanced draw calls.

+ 12 - 0
Engine/Graphics/Renderer.cpp

@@ -276,6 +276,8 @@ Renderer::Renderer(Context* context) :
     shadowMapHiresDepth_(false),
     shadowMapHiresDepth_(false),
     reuseShadowMaps_(true),
     reuseShadowMaps_(true),
     dynamicInstancing_(true),
     dynamicInstancing_(true),
+    minInstanceGroupSize_(4),
+    maxInstanceTriangles_(500),
     maxOccluderTriangles_(5000),
     maxOccluderTriangles_(5000),
     occlusionBufferSize_(256),
     occlusionBufferSize_(256),
     occluderSizeThreshold_(0.1f),
     occluderSizeThreshold_(0.1f),
@@ -419,6 +421,16 @@ void Renderer::SetDynamicInstancing(bool enable)
     dynamicInstancing_ = enable;
     dynamicInstancing_ = enable;
 }
 }
 
 
+void Renderer::SetMinInstanceGroupSize(int size)
+{
+    minInstanceGroupSize_ = Max(size, 2);
+}
+
+void Renderer::SetMaxInstanceTriangles(int triangles)
+{
+    maxInstanceTriangles_ = Max(triangles, 0);
+}
+
 void Renderer::SetMaxOccluderTriangles(int triangles)
 void Renderer::SetMaxOccluderTriangles(int triangles)
 {
 {
     maxOccluderTriangles_ = Max(triangles, 0);
     maxOccluderTriangles_ = Max(triangles, 0);

+ 12 - 1
Engine/Graphics/Renderer.h

@@ -48,7 +48,6 @@ class Zone;
 
 
 static const int SHADOW_MIN_PIXELS = 64;
 static const int SHADOW_MIN_PIXELS = 64;
 static const int NUM_SHADOWMAP_RESOLUTIONS = 3;
 static const int NUM_SHADOWMAP_RESOLUTIONS = 3;
-static const int MIN_INSTANCES = 4;
 static const int INSTANCING_BUFFER_DEFAULT_SIZE = 1024;
 static const int INSTANCING_BUFFER_DEFAULT_SIZE = 1024;
 
 
 /// Light vertex shader variations.
 /// Light vertex shader variations.
@@ -170,6 +169,10 @@ public:
     void SetNumShadowMaps(unsigned full, unsigned half, unsigned quarter);
     void SetNumShadowMaps(unsigned full, unsigned half, unsigned quarter);
     /// %Set dynamic instancing on/off.
     /// %Set dynamic instancing on/off.
     void SetDynamicInstancing(bool enable);
     void SetDynamicInstancing(bool enable);
+    /// %Set minimum object group size for instancing.
+    void SetMinInstanceGroupSize(int size);
+    /// %Set maximum number of triangles per object for instancing.
+    void SetMaxInstanceTriangles(int triangles);
     /// %Set maximum number of occluder trianges.
     /// %Set maximum number of occluder trianges.
     void SetMaxOccluderTriangles(int triangles);
     void SetMaxOccluderTriangles(int triangles);
     /// %Set occluder buffer width.
     /// %Set occluder buffer width.
@@ -206,6 +209,10 @@ public:
     unsigned GetNumQuarterShadowMaps() const { return shadowMaps_[2].Size(); }
     unsigned GetNumQuarterShadowMaps() const { return shadowMaps_[2].Size(); }
     /// Return whether dynamic instancing is in use.
     /// Return whether dynamic instancing is in use.
     bool GetDynamicInstancing() const { return dynamicInstancing_; }
     bool GetDynamicInstancing() const { return dynamicInstancing_; }
+    /// Return minimum object group size for instancing.
+    int GetMinInstanceGroupSize() const { return minInstanceGroupSize_; }
+    /// Return maximum number of triangles per object for instancing.
+    int GetMaxInstanceTriangles() { return maxInstanceTriangles_; }
     /// Return maximum number of occluder triangles.
     /// Return maximum number of occluder triangles.
     int GetMaxOccluderTriangles() const { return maxOccluderTriangles_; }
     int GetMaxOccluderTriangles() const { return maxOccluderTriangles_; }
     /// Return occlusion buffer width.
     /// Return occlusion buffer width.
@@ -392,6 +399,10 @@ private:
     bool reuseShadowMaps_;
     bool reuseShadowMaps_;
     /// Dynamic instancing flag.
     /// Dynamic instancing flag.
     bool dynamicInstancing_;
     bool dynamicInstancing_;
+    /// Minimum object group size for instancing.
+    int minInstanceGroupSize_;
+    /// Maximum triangles per object for instancing.
+    int maxInstanceTriangles_;
     /// Maximum occluder triangles.
     /// Maximum occluder triangles.
     int maxOccluderTriangles_;
     int maxOccluderTriangles_;
     /// Occlusion buffer width.
     /// Occlusion buffer width.

+ 10 - 10
Engine/Graphics/View.cpp

@@ -1915,14 +1915,14 @@ void View::PrepareInstancingBuffer()
     unsigned totalInstances = 0;
     unsigned totalInstances = 0;
     
     
     if (mode_ != RENDER_FORWARD)
     if (mode_ != RENDER_FORWARD)
-        totalInstances += gBufferQueue_.GetNumInstances();
-    totalInstances += baseQueue_.GetNumInstances();
-    totalInstances += extraQueue_.GetNumInstances();
+        totalInstances += gBufferQueue_.GetNumInstances(renderer_);
+    totalInstances += baseQueue_.GetNumInstances(renderer_);
+    totalInstances += extraQueue_.GetNumInstances(renderer_);
     
     
     for (unsigned i = 0; i < lightQueues_.Size(); ++i)
     for (unsigned i = 0; i < lightQueues_.Size(); ++i)
     {
     {
-        totalInstances += lightQueues_[i].shadowBatches_.GetNumInstances();
-        totalInstances += lightQueues_[i].litBatches_.GetNumInstances();
+        totalInstances += lightQueues_[i].shadowBatches_.GetNumInstances(renderer_);
+        totalInstances += lightQueues_[i].litBatches_.GetNumInstances(renderer_);
     }
     }
     
     
     // If fail to set buffer size, fall back to per-group locking
     // If fail to set buffer size, fall back to per-group locking
@@ -1933,14 +1933,14 @@ void View::PrepareInstancingBuffer()
         if (lockedData)
         if (lockedData)
         {
         {
             if (mode_ != RENDER_FORWARD)
             if (mode_ != RENDER_FORWARD)
-                gBufferQueue_.SetTransforms(lockedData, freeIndex);
-            baseQueue_.SetTransforms(lockedData, freeIndex);
-            extraQueue_.SetTransforms(lockedData, freeIndex);
+                gBufferQueue_.SetTransforms(renderer_, lockedData, freeIndex);
+            baseQueue_.SetTransforms(renderer_, lockedData, freeIndex);
+            extraQueue_.SetTransforms(renderer_, lockedData, freeIndex);
             
             
             for (unsigned i = 0; i < lightQueues_.Size(); ++i)
             for (unsigned i = 0; i < lightQueues_.Size(); ++i)
             {
             {
-                lightQueues_[i].shadowBatches_.SetTransforms(lockedData, freeIndex);
-                lightQueues_[i].litBatches_.SetTransforms(lockedData, freeIndex);
+                lightQueues_[i].shadowBatches_.SetTransforms(renderer_, lockedData, freeIndex);
+                lightQueues_[i].litBatches_.SetTransforms(renderer_, lockedData, freeIndex);
             }
             }
             
             
             renderer_->instancingBuffer_->Unlock();
             renderer_->instancingBuffer_->Unlock();