Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Bolsee <benoit.bolsee@online.be>2009-05-07 13:13:01 +0400
committerBenoit Bolsee <benoit.bolsee@online.be>2009-05-07 13:13:01 +0400
commit42557f90bd16771a5c6437dbfb3952527df7fb1a (patch)
tree783a84eef7c05adbea3015ecd09ec7e2b18a7cfa /source/gameengine/Rasterizer
parent779bf435ef2ba87fbcee6a28b053d97a551b8eb5 (diff)
BGE performance, 3rd round: culling and rasterizer.
This commit extend the technique of dynamic linked list to the mesh slots so as to eliminate dumb scan or map lookup. It provides massive performance improvement in the culling and in the rasterizer when the majority of objects are static. Other improvements: - Compute the opengl matrix only for objects that are visible. - Simplify hash function for GEN_HasedPtr - Scan light list instead of general object list to render shadows - Remove redundant opengl calls to set specularity, shinyness and diffuse between each mesh slots. - Cache GPU material to avoid frequent call to GPU_material_from_blender - Only set once the fixed elements of mesh slot - Use more inline function The following table shows the performance increase between 2.48, 1st round and this round of improvement. The test was done with a scene containing 40000 objects, of which 1000 are in the view frustrum approximately. The object are simple textured cube to make sure the GPU is not the bottleneck. As some of the rasterizer processing time has moved under culling, I present the sum of scenegraph(includes culling)+rasterizer time Scenegraph+rasterizer(ms) 2.48 1st round 3rd round All objects static, 323.0 86.0 7.2 all visible, 1000 in the view frustrum All objects static, 219.0 49.7 N/A(*) all invisible. All objects moving, 323.0 105.6 34.7 all visible, 1000 in the view frustrum Scene destruction 40min 40min 4s (*) : this time is not representative because the frame rate was at 60fps. In that case, the GPU holds down the GE by frame sync. By design, the overhead of the rasterizer is 0 when the the objects are invisible. This table shows a global speed up between 9x and 45x compared to 2.48a for scenegraph, culling and rasterizer overhead. The speed up goes much higher when objects are invisible. An additional 2-4x speed up is possible in the scenegraph by upgrading the Moto library to use Eigen2 BLAS library instead of C++ classes but the scenegraph is already so fast that it is not a priority right now. Next speed up in logic: many things to do there...
Diffstat (limited to 'source/gameengine/Rasterizer')
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt1
-rw-r--r--source/gameengine/Rasterizer/Makefile1
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.cpp60
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.h1
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp3
-rw-r--r--source/gameengine/Rasterizer/RAS_IPolygonMaterial.h1
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.cpp12
-rw-r--r--source/gameengine/Rasterizer/RAS_MaterialBucket.h25
-rw-r--r--source/gameengine/Rasterizer/RAS_MeshObject.cpp8
-rw-r--r--source/gameengine/Rasterizer/RAS_MeshObject.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt1
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile1
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript2
-rw-r--r--source/gameengine/Rasterizer/SConscript2
15 files changed, 106 insertions, 16 deletions
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index 69a167e54a9..143209f5a54 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -30,6 +30,7 @@ SET(INC
.
../../../source/kernel/gen_system
../../../source/blender/makesdna
+ ../../../source/gameengine/SceneGraph
../../../intern/string
../../../intern/moto/include
../../../extern/glew/include
diff --git a/source/gameengine/Rasterizer/Makefile b/source/gameengine/Rasterizer/Makefile
index fa6cf94c4b6..eafa2ded2f2 100644
--- a/source/gameengine/Rasterizer/Makefile
+++ b/source/gameengine/Rasterizer/Makefile
@@ -41,6 +41,7 @@ CPPFLAGS += -I$(NAN_STRING)/include
CPPFLAGS += -I$(NAN_MOTO)/include
CPPFLAGS += -I../../kernel/gen_system
CPPFLAGS += -I../../blender/makesdna
+CPPFLAGS += -I../SceneGraph
CPPFLAGS += -I../BlenderRoutines
CPPFLAGS += -I../Expressions
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
index ec290f89d9e..a111ac2786f 100644
--- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
@@ -113,16 +113,38 @@ void RAS_BucketManager::OrderBuckets(const MT_Transform& cameratrans, BucketList
const MT_Vector3 pnorm(cameratrans.getBasis()[2]);
for (bit = buckets.begin(); bit != buckets.end(); ++bit)
+ {
+#if 1
+ SG_DList::iterator<RAS_MeshSlot> mit((*bit)->GetActiveMeshSlots());
+ for(mit.begin(); !mit.end(); ++mit)
+ size++;
+#else
for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit)
if (!mit->IsCulled())
size++;
+#endif
+ }
slots.resize(size);
for (bit = buckets.begin(); bit != buckets.end(); ++bit)
+ {
+#if 1
+ RAS_MaterialBucket* bucket = *bit;
+ RAS_MeshSlot* ms;
+ // remove the mesh slot form the list, it culls them automatically for next frame
+ for(ms = bucket->GetNextActiveMeshSlot();
+ ms!= NULL;
+ ms = bucket->GetNextActiveMeshSlot())
+ {
+ slots[i++].set(ms, bucket, pnorm);
+ }
+#else
for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit)
if (!mit->IsCulled())
slots[i++].set(&*mit, *bit, pnorm);
+#endif
+ }
if(alpha)
sort(slots.begin(), slots.end(), backtofront());
@@ -161,11 +183,28 @@ void RAS_BucketManager::RenderSolidBuckets(
const MT_Transform& cameratrans, RAS_IRasterizer* rasty, RAS_IRenderTools* rendertools)
{
BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
rasty->SetDepthMask(RAS_IRasterizer::KX_DEPTHMASK_ENABLED);
for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
+#if 1
+ RAS_MaterialBucket* bucket = *bit;
+ RAS_MeshSlot* ms;
+ // remove the mesh slot form the list, it culls them automatically for next frame
+ for(ms = bucket->GetNextActiveMeshSlot();
+ ms!= NULL;
+ ms = bucket->GetNextActiveMeshSlot())
+ {
+ rendertools->SetClientObject(rasty, ms->m_clientObj);
+ while (bucket->ActivateMaterial(cameratrans, rasty, rendertools))
+ bucket->RenderMeshSlot(cameratrans, rasty, rendertools, *ms);
+
+ // make this mesh slot culled automatically for next frame
+ // it will be culled out by frustrum culling
+ ms->SetCulled(true);
+ }
+#else
+ list<RAS_MeshSlot>::iterator mit;
for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
if (mit->IsCulled())
continue;
@@ -179,6 +218,7 @@ void RAS_BucketManager::RenderSolidBuckets(
// it will be culled out by frustrum culling
mit->SetCulled(true);
}
+#endif
}
/* this code draws meshes order front-to-back instead to reduce overdraw.
@@ -276,3 +316,21 @@ void RAS_BucketManager::ReleaseDisplayLists(RAS_IPolyMaterial *mat)
}
}
+void RAS_BucketManager::ReleaseMaterials(RAS_IPolyMaterial * mat)
+{
+ BucketList::iterator bit;
+ list<RAS_MeshSlot>::iterator mit;
+
+ for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
+ if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
+ (*bit)->GetPolyMaterial()->ReleaseMaterial();
+ }
+ }
+
+ for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
+ if (mat == NULL || (mat == (*bit)->GetPolyMaterial())) {
+ (*bit)->GetPolyMaterial()->ReleaseMaterial();
+ }
+ }
+}
+
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h
index 74526f365a0..2b81ddd3c82 100644
--- a/source/gameengine/Rasterizer/RAS_BucketManager.h
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.h
@@ -58,6 +58,7 @@ public:
void OptimizeBuckets(MT_Scalar distance);
void ReleaseDisplayLists(RAS_IPolyMaterial * material = NULL);
+ void ReleaseMaterials(RAS_IPolyMaterial * material = NULL);
private:
void OrderBuckets(const MT_Transform& cameratrans, BucketList& buckets, vector<sortedmeshslot>& slots, bool alpha);
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
index c10e4040a92..f2fd96d63e9 100644
--- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.cpp
@@ -227,6 +227,9 @@ Scene* RAS_IPolyMaterial::GetBlenderScene() const
return NULL;
}
+void RAS_IPolyMaterial::ReleaseMaterial()
+{
+}
unsigned int RAS_IPolyMaterial::GetFlag() const
{
diff --git a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
index 1bc03a1db05..decd93c3d13 100644
--- a/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
+++ b/source/gameengine/Rasterizer/RAS_IPolygonMaterial.h
@@ -160,6 +160,7 @@ public:
virtual Material* GetBlenderMaterial() const;
virtual Scene* GetBlenderScene() const;
+ virtual void ReleaseMaterial();
virtual void GetMaterialRGBAColor(unsigned char *rgba) const;
virtual bool UsesLighting(RAS_IRasterizer *rasty) const;
virtual bool UsesObjectColor() const;
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
index d63e9c98415..db6394c1ec0 100644
--- a/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.cpp
@@ -42,7 +42,7 @@
/* mesh slot */
-RAS_MeshSlot::RAS_MeshSlot()
+RAS_MeshSlot::RAS_MeshSlot() : SG_QList()
{
m_clientObj = NULL;
m_pDeformer = NULL;
@@ -82,7 +82,7 @@ RAS_MeshSlot::~RAS_MeshSlot()
}
}
-RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot)
+RAS_MeshSlot::RAS_MeshSlot(const RAS_MeshSlot& slot) : SG_QList()
{
RAS_DisplayArrayList::iterator it;
@@ -461,21 +461,21 @@ bool RAS_MeshSlot::Split(bool force)
return false;
}
+
+#ifdef USE_SPLIT
bool RAS_MeshSlot::IsCulled()
{
- list<RAS_MeshSlot*>::iterator it;
-
if(m_joinSlot)
return true;
if(!m_bCulled)
return false;
-#ifdef USE_SPLIT
+ list<RAS_MeshSlot*>::iterator it;
for(it=m_joinedSlots.begin(); it!=m_joinedSlots.end(); it++)
if(!(*it)->m_bCulled)
return false;
-#endif
return true;
}
+#endif
/* material bucket sorting */
diff --git a/source/gameengine/Rasterizer/RAS_MaterialBucket.h b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
index b07f86b079e..8db75b8b735 100644
--- a/source/gameengine/Rasterizer/RAS_MaterialBucket.h
+++ b/source/gameengine/Rasterizer/RAS_MaterialBucket.h
@@ -32,6 +32,7 @@
#include "RAS_TexVert.h"
#include "GEN_Map.h"
#include "STR_HashedString.h"
+#include "SG_QList.h"
#include "MT_Transform.h"
#include "RAS_IPolygonMaterial.h"
@@ -89,7 +90,9 @@ public:
/* Entry of a RAS_MeshObject into RAS_MaterialBucket */
typedef std::vector<RAS_DisplayArray*> RAS_DisplayArrayList;
-class RAS_MeshSlot
+// The QList is used to link the mesh slots to the object
+// The DList is used to link the visible mesh slots to the material bucket
+class RAS_MeshSlot : public SG_QList
{
friend class RAS_ListRasterizer;
private:
@@ -160,7 +163,11 @@ public:
bool Split(bool force=false);
bool Join(RAS_MeshSlot *target, MT_Scalar distance);
bool Equals(RAS_MeshSlot *target);
+#ifdef USE_SPLIT
bool IsCulled();
+#else
+ bool IsCulled() { return m_bCulled; }
+#endif
void SetCulled(bool culled) { m_bCulled = culled; }
};
@@ -171,7 +178,6 @@ class RAS_MeshMaterial
public:
RAS_MeshSlot *m_baseslot;
class RAS_MaterialBucket *m_bucket;
-
GEN_Map<GEN_HashedPtr,RAS_MeshSlot*> m_slots;
};
@@ -208,10 +214,23 @@ public:
class RAS_MeshSlot* CopyMesh(class RAS_MeshSlot *ms);
void RemoveMesh(class RAS_MeshSlot* ms);
void Optimize(MT_Scalar distance);
+ void ActivateMesh(RAS_MeshSlot* slot)
+ {
+ m_activeMeshSlotsHead.AddBack(slot);
+ }
+ SG_DList& GetActiveMeshSlots()
+ {
+ return m_activeMeshSlotsHead;
+ }
+ RAS_MeshSlot* GetNextActiveMeshSlot()
+ {
+ return (RAS_MeshSlot*)m_activeMeshSlotsHead.Remove();
+ }
private:
- list<RAS_MeshSlot> m_meshSlots;
+ list<RAS_MeshSlot> m_meshSlots; // all the mesh slots
RAS_IPolyMaterial* m_material;
+ SG_DList m_activeMeshSlotsHead; // only those which must be rendered
};
diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.cpp b/source/gameengine/Rasterizer/RAS_MeshObject.cpp
index 278aa9c75e2..c3223cb9448 100644
--- a/source/gameengine/Rasterizer/RAS_MeshObject.cpp
+++ b/source/gameengine/Rasterizer/RAS_MeshObject.cpp
@@ -242,6 +242,7 @@ RAS_Polygon* RAS_MeshObject::AddPolygon(RAS_MaterialBucket *bucket, int numverts
RAS_MeshMaterial meshmat;
meshmat.m_bucket = bucket;
meshmat.m_baseslot = meshmat.m_bucket->AddMesh(numverts);
+ meshmat.m_baseslot->m_mesh = this;
m_materials.push_back(meshmat);
mmat = &m_materials.back();
}
@@ -381,7 +382,7 @@ RAS_TexVert* RAS_MeshObject::GetVertex(unsigned int matid,
return NULL;
}
-void RAS_MeshObject::AddMeshUser(void *clientobj)
+void RAS_MeshObject::AddMeshUser(void *clientobj, SG_QList *head)
{
list<RAS_MeshMaterial>::iterator it;
@@ -391,6 +392,7 @@ void RAS_MeshObject::AddMeshUser(void *clientobj)
RAS_MeshSlot *ms = it->m_bucket->CopyMesh(it->m_baseslot);
ms->m_clientObj = clientobj;
it->m_slots.insert(clientobj, ms);
+ head->QAddBack(ms);
}
}
@@ -402,7 +404,7 @@ void RAS_MeshObject::UpdateBuckets(void* clientobj,
bool culled)
{
list<RAS_MeshMaterial>::iterator it;
-
+
for(it = m_materials.begin();it!=m_materials.end();++it) {
RAS_MeshSlot **msp = it->m_slots[clientobj];
@@ -417,6 +419,8 @@ void RAS_MeshObject::UpdateBuckets(void* clientobj,
ms->m_RGBAcolor = rgbavec;
ms->m_bVisible = visible;
ms->m_bCulled = culled || !visible;
+ if (!ms->m_bCulled)
+ ms->m_bucket->ActivateMesh(ms);
/* split if necessary */
#ifdef USE_SPLIT
diff --git a/source/gameengine/Rasterizer/RAS_MeshObject.h b/source/gameengine/Rasterizer/RAS_MeshObject.h
index cc50f9c783d..a2283b9bc5d 100644
--- a/source/gameengine/Rasterizer/RAS_MeshObject.h
+++ b/source/gameengine/Rasterizer/RAS_MeshObject.h
@@ -130,7 +130,7 @@ public:
RAS_Polygon* GetPolygon(int num) const;
/* buckets */
- virtual void AddMeshUser(void *clientobj);
+ virtual void AddMeshUser(void *clientobj, SG_QList *head);
virtual void UpdateBuckets(
void* clientobj,
double* oglmatrix,
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
index d061a449b7e..fe3d0f6aeea 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -32,6 +32,7 @@ SET(INC
../../../../intern/moto/include
../../../../source/gameengine/Rasterizer
../../../../source/gameengine/Ketsji
+ ../../../../source/gameengine/SceneGraph
../../../../extern/glew/include
../../../../source/blender/gpu
../../../../source/blender/makesdna
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile
index b55f6492805..0327714dc5f 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/Makefile
@@ -47,6 +47,7 @@ CPPFLAGS += -I../../../blender/blenlib
CPPFLAGS += -I../../../blender/blenkernel
CPPFLAGS += -I../../BlenderRoutines
CPPFLAGS += -I../../Ketsji
+CPPFLAGS += -I../../SceneGraph
CPPFLAGS += -I..
CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index 06c61fb4b09..3ae4522f8e1 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -214,7 +214,7 @@ void RAS_ListRasterizer::IndexPrimitivesMulti(RAS_MeshSlot& ms)
// workaround: note how we do not use vertex arrays for making display
// lists, since glVertexAttribPointerARB doesn't seem to work correct
// in display lists on ATI? either a bug in the driver or in Blender ..
- if (mUseVertexArrays && !localSlot && !ms.m_pDerivedMesh)
+ if (mUseVertexArrays && /*!localSlot &&*/ !ms.m_pDerivedMesh)
RAS_VAOpenGLRasterizer::IndexPrimitivesMulti(ms);
else
RAS_OpenGLRasterizer::IndexPrimitivesMulti(ms);
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
index 314630297e0..d4b029ea34d 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
@@ -5,7 +5,7 @@ sources = env.Glob('*.cpp')
incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/Rasterizer #source/gameengine/BlenderRoutines '
incs += ' #source/blender/gpu #extern/glew/include ' + env['BF_OPENGL_INC']
-incs += ' #source/blender/gameengine/Ketsji #source/blender/makesdna #source/blender/blenkernel'
+incs += ' #source/blender/gameengine/Ketsji #source/gameengine/SceneGraph #source/blender/makesdna #source/blender/blenkernel'
incs += ' #intern/guardedalloc #source/blender/blenlib'
cxxflags = []
diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript
index a16a04b8514..771d3399485 100644
--- a/source/gameengine/Rasterizer/SConscript
+++ b/source/gameengine/Rasterizer/SConscript
@@ -4,7 +4,7 @@ Import ('env')
sources = env.Glob('*.cpp')
-incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions #source/blender/blenkernel #source/blender/makesdna'
+incs = '. #source/kernel/gen_system #intern/string #intern/moto/include #source/gameengine/BlenderRoutines #extern/glew/include #source/gameengine/Expressions #source/gameengine/SceneGraph #source/blender/blenkernel #source/blender/makesdna'
incs += ' ' + env['BF_PYTHON_INC']
cxxflags = []