Browse Source

Possibility in DecalSet to size VB/IB to only size used by decals. Default off; causes reallocation whenever decals are added/removed and thus can have worse performance.

Lasse Öörni 9 years ago
parent
commit
0ea9ed6e34

+ 2 - 0
Source/Urho3D/AngelScript/GraphicsAPI.cpp

@@ -1738,6 +1738,8 @@ static void RegisterDecalSet(asIScriptEngine* engine)
     engine->RegisterObjectMethod("DecalSet", "uint get_maxVertices() const", asMETHOD(DecalSet, GetMaxVertices), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "uint get_maxVertices() const", asMETHOD(DecalSet, GetMaxVertices), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void set_maxIndices(uint)", asMETHOD(DecalSet, SetMaxIndices), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "void set_maxIndices(uint)", asMETHOD(DecalSet, SetMaxIndices), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "uint get_maxIndices() const", asMETHOD(DecalSet, GetMaxIndices), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "uint get_maxIndices() const", asMETHOD(DecalSet, GetMaxIndices), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DecalSet", "void set_optimizeBufferSize(bool)", asMETHOD(DecalSet, SetOptimizeBufferSize), asCALL_THISCALL);
+    engine->RegisterObjectMethod("DecalSet", "bool get_optimizeBufferSize() const", asMETHOD(DecalSet, GetOptimizeBufferSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "Zone@+ get_zone() const", asMETHOD(DecalSet, GetZone), asCALL_THISCALL);
     engine->RegisterObjectMethod("DecalSet", "Zone@+ get_zone() const", asMETHOD(DecalSet, GetZone), asCALL_THISCALL);
 }
 }
 
 

+ 31 - 22
Source/Urho3D/Graphics/DecalSet.cpp

@@ -160,8 +160,8 @@ DecalSet::DecalSet(Context* context) :
     numIndices_(0),
     numIndices_(0),
     maxVertices_(DEFAULT_MAX_VERTICES),
     maxVertices_(DEFAULT_MAX_VERTICES),
     maxIndices_(DEFAULT_MAX_INDICES),
     maxIndices_(DEFAULT_MAX_INDICES),
+    optimizeBufferSize_(false),
     skinned_(false),
     skinned_(false),
-    bufferSizeDirty_(true),
     bufferDirty_(true),
     bufferDirty_(true),
     boundingBoxDirty_(true),
     boundingBoxDirty_(true),
     skinningDirty_(false),
     skinningDirty_(false),
@@ -188,6 +188,7 @@ void DecalSet::RegisterObject(Context* context)
         AM_DEFAULT);
         AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max Vertices", GetMaxVertices, SetMaxVertices, unsigned, DEFAULT_MAX_VERTICES, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max Vertices", GetMaxVertices, SetMaxVertices, unsigned, DEFAULT_MAX_VERTICES, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max Indices", GetMaxIndices, SetMaxIndices, unsigned, DEFAULT_MAX_INDICES, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Max Indices", GetMaxIndices, SetMaxIndices, unsigned, DEFAULT_MAX_INDICES, AM_DEFAULT);
+    URHO3D_ACCESSOR_ATTRIBUTE("Optimize Buffer Size", GetOptimizeBufferSize, SetOptimizeBufferSize, bool, false, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     URHO3D_ACCESSOR_ATTRIBUTE("Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     URHO3D_COPY_BASE_ATTRIBUTES(Drawable);
     URHO3D_COPY_BASE_ATTRIBUTES(Drawable);
@@ -229,9 +230,6 @@ void DecalSet::UpdateBatches(const FrameInfo& frame)
 
 
 void DecalSet::UpdateGeometry(const FrameInfo& frame)
 void DecalSet::UpdateGeometry(const FrameInfo& frame)
 {
 {
-    if (bufferSizeDirty_)
-        UpdateBufferSize();
-
     if (bufferDirty_ || vertexBuffer_->IsDataLost() || indexBuffer_->IsDataLost())
     if (bufferDirty_ || vertexBuffer_->IsDataLost() || indexBuffer_->IsDataLost())
         UpdateBuffers();
         UpdateBuffers();
 
 
@@ -241,7 +239,7 @@ void DecalSet::UpdateGeometry(const FrameInfo& frame)
 
 
 UpdateGeometryType DecalSet::GetUpdateGeometryType()
 UpdateGeometryType DecalSet::GetUpdateGeometryType()
 {
 {
-    if (bufferDirty_ || bufferSizeDirty_ || vertexBuffer_->IsDataLost() || indexBuffer_->IsDataLost())
+    if (bufferDirty_ || vertexBuffer_->IsDataLost() || indexBuffer_->IsDataLost())
         return UPDATE_MAIN_THREAD;
         return UPDATE_MAIN_THREAD;
     else if (skinningDirty_)
     else if (skinningDirty_)
         return UPDATE_WORKER_THREAD;
         return UPDATE_WORKER_THREAD;
@@ -262,7 +260,8 @@ void DecalSet::SetMaxVertices(unsigned num)
 
 
     if (num != maxVertices_)
     if (num != maxVertices_)
     {
     {
-        bufferSizeDirty_ = true;
+        if (!optimizeBufferSize_)
+            bufferDirty_ = true;
         maxVertices_ = num;
         maxVertices_ = num;
 
 
         while (decals_.Size() && numVertices_ > maxVertices_)
         while (decals_.Size() && numVertices_ > maxVertices_)
@@ -279,7 +278,8 @@ void DecalSet::SetMaxIndices(unsigned num)
 
 
     if (num != maxIndices_)
     if (num != maxIndices_)
     {
     {
-        bufferSizeDirty_ = true;
+        if (!optimizeBufferSize_)
+            bufferDirty_ = true;
         maxIndices_ = num;
         maxIndices_ = num;
 
 
         while (decals_.Size() && numIndices_ > maxIndices_)
         while (decals_.Size() && numIndices_ > maxIndices_)
@@ -289,6 +289,17 @@ void DecalSet::SetMaxIndices(unsigned num)
     }
     }
 }
 }
 
 
+void DecalSet::SetOptimizeBufferSize(bool enable)
+{
+    if (enable != optimizeBufferSize_)
+    {
+        optimizeBufferSize_ = enable;
+        bufferDirty_ = true;
+
+        MarkNetworkUpdate();
+    }
+}
+
 bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size,
 bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size,
     float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff,
     float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive, float normalCutoff,
     unsigned subGeometry)
     unsigned subGeometry)
@@ -311,7 +322,7 @@ bool DecalSet::AddDecal(Drawable* target, const Vector3& worldPosition, const Qu
     {
     {
         RemoveAllDecals();
         RemoveAllDecals();
         skinned_ = animatedModel != 0;
         skinned_ = animatedModel != 0;
-        bufferSizeDirty_ = true;
+        bufferDirty_ = true;
     }
     }
 
 
     // Center the decal frustum on the world position
     // Center the decal frustum on the world position
@@ -583,7 +594,6 @@ void DecalSet::SetDecalsAttr(const PODVector<unsigned char>& value)
     UpdateEventSubscription(true);
     UpdateEventSubscription(true);
     UpdateBatch();
     UpdateBatch();
     MarkDecalsDirty();
     MarkDecalsDirty();
-    bufferSizeDirty_ = true;
 }
 }
 
 
 ResourceRef DecalSet::GetMaterialAttr() const
 ResourceRef DecalSet::GetMaterialAttr() const
@@ -1000,22 +1010,21 @@ void DecalSet::CalculateBoundingBox()
     boundingBoxDirty_ = false;
     boundingBoxDirty_ = false;
 }
 }
 
 
-void DecalSet::UpdateBufferSize()
-{
-    vertexBuffer_->SetSize(maxVertices_, skinned_ ? SKINNED_ELEMENT_MASK : STATIC_ELEMENT_MASK);
-    indexBuffer_->SetSize(maxIndices_, false);
-    geometry_->SetVertexBuffer(0, vertexBuffer_);
-
-    bufferDirty_ = true;
-    bufferSizeDirty_ = false;
-}
-
 void DecalSet::UpdateBuffers()
 void DecalSet::UpdateBuffers()
 {
 {
+    unsigned newElementMask = skinned_ ? SKINNED_ELEMENT_MASK : STATIC_ELEMENT_MASK;
+    unsigned newVBSize = optimizeBufferSize_ ? numVertices_ : maxVertices_;
+    unsigned newIBSize = optimizeBufferSize_ ? numIndices_ : maxIndices_;
+    
+    if (vertexBuffer_->GetElementMask() != newElementMask || vertexBuffer_->GetVertexCount() != newVBSize)
+        vertexBuffer_->SetSize(newVBSize, newElementMask);
+    if (indexBuffer_->GetIndexCount() != newIBSize)
+        indexBuffer_->SetSize(newIBSize, false);
+    geometry_->SetVertexBuffer(0, vertexBuffer_);
     geometry_->SetDrawRange(TRIANGLE_LIST, 0, numIndices_, 0, numVertices_);
     geometry_->SetDrawRange(TRIANGLE_LIST, 0, numIndices_, 0, numVertices_);
-
-    float* vertices = (float*)vertexBuffer_->Lock(0, numVertices_);
-    unsigned short* indices = (unsigned short*)indexBuffer_->Lock(0, numIndices_);
+    
+    float* vertices = numVertices_ ? (float*)vertexBuffer_->Lock(0, numVertices_) : (float*)0;
+    unsigned short* indices = numIndices_ ? (unsigned short*)indexBuffer_->Lock(0, numIndices_) : (unsigned short*)0;
 
 
     if (vertices && indices)
     if (vertices && indices)
     {
     {

+ 8 - 3
Source/Urho3D/Graphics/DecalSet.h

@@ -133,6 +133,8 @@ public:
     void SetMaxVertices(unsigned num);
     void SetMaxVertices(unsigned num);
     /// Set maximum number of decal vertex indices.
     /// Set maximum number of decal vertex indices.
     void SetMaxIndices(unsigned num);
     void SetMaxIndices(unsigned num);
+    /// Set whether to optimize GPU buffer sizes according to current amount of decals. Default false, which will size the buffers according to the maximum vertices/indices. When true, buffers will be reallocated whenever decals are added/removed, which can be worse for performance.
+    void SetOptimizeBufferSize(bool enable);
     /// Add a decal at world coordinates, using a target drawable's geometry for reference. If the decal needs to move with the target, the decal component should be created to the target's node. Return true if successful.
     /// Add a decal at world coordinates, using a target drawable's geometry for reference. If the decal needs to move with the target, the decal component should be created to the target's node. Return true if successful.
     bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio,
     bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio,
         float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f,
         float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f,
@@ -159,6 +161,9 @@ public:
 
 
     /// Return maximum number of decal vertex indices.
     /// Return maximum number of decal vertex indices.
     unsigned GetMaxIndices() const { return maxIndices_; }
     unsigned GetMaxIndices() const { return maxIndices_; }
+    
+    /// Return whether is optimizing GPU buffer sizes according to current amount of decals.
+    bool GetOptimizeBufferSize() const { return optimizeBufferSize_; }
 
 
     /// Set material attribute.
     /// Set material attribute.
     void SetMaterialAttr(const ResourceRef& value);
     void SetMaterialAttr(const ResourceRef& value);
@@ -234,11 +239,11 @@ private:
     unsigned maxVertices_;
     unsigned maxVertices_;
     /// Maximum indices.
     /// Maximum indices.
     unsigned maxIndices_;
     unsigned maxIndices_;
+    /// Optimize buffer sizes flag.
+    bool optimizeBufferSize_;
     /// Skinned mode flag.
     /// Skinned mode flag.
     bool skinned_;
     bool skinned_;
-    /// Vertex buffer needs resize flag.
-    bool bufferSizeDirty_;
-    /// Vertex buffer needs rewrite flag.
+    /// Vertex buffer needs rewrite / resizing flag.
     bool bufferDirty_;
     bool bufferDirty_;
     /// Bounding box needs update flag.
     /// Bounding box needs update flag.
     bool boundingBoxDirty_;
     bool boundingBoxDirty_;

+ 5 - 2
Source/Urho3D/LuaScript/pkgs/Graphics/DecalSet.pkg

@@ -5,21 +5,24 @@ class DecalSet : public Drawable
     void SetMaterial(Material* material);
     void SetMaterial(Material* material);
     void SetMaxVertices(unsigned num);
     void SetMaxVertices(unsigned num);
     void SetMaxIndices(unsigned num);
     void SetMaxIndices(unsigned num);
+    void SetOptimizeBufferSize(bool enable);
     bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f, unsigned subGeometry = M_MAX_UNSIGNED);
     bool AddDecal(Drawable* target, const Vector3& worldPosition, const Quaternion& worldRotation, float size, float aspectRatio, float depth, const Vector2& topLeftUV, const Vector2& bottomRightUV, float timeToLive = 0.0f, float normalCutoff = 0.1f, unsigned subGeometry = M_MAX_UNSIGNED);
     void RemoveDecals(unsigned num);
     void RemoveDecals(unsigned num);
     void RemoveAllDecals();
     void RemoveAllDecals();
-    
+
     Material* GetMaterial() const;
     Material* GetMaterial() const;
     unsigned GetNumDecals() const;
     unsigned GetNumDecals() const;
     unsigned GetNumVertices() const;
     unsigned GetNumVertices() const;
     unsigned GetNumIndices() const;
     unsigned GetNumIndices() const;
     unsigned GetMaxVertices() const;
     unsigned GetMaxVertices() const;
     unsigned GetMaxIndices() const;
     unsigned GetMaxIndices() const;
-    
+    bool GetOptimizeBufferSize() const;
+
     tolua_property__get_set Material* material;
     tolua_property__get_set Material* material;
     tolua_readonly tolua_property__get_set unsigned numDecals;
     tolua_readonly tolua_property__get_set unsigned numDecals;
     tolua_readonly tolua_property__get_set unsigned numVertices;
     tolua_readonly tolua_property__get_set unsigned numVertices;
     tolua_readonly tolua_property__get_set unsigned numIndices;
     tolua_readonly tolua_property__get_set unsigned numIndices;
     tolua_property__get_set unsigned maxVertices;
     tolua_property__get_set unsigned maxVertices;
     tolua_property__get_set unsigned maxIndices;
     tolua_property__get_set unsigned maxIndices;
+    tolua_property__get_set bool optimizeBufferSize;
 };
 };