From 42557f90bd16771a5c6437dbfb3952527df7fb1a Mon Sep 17 00:00:00 2001 From: Benoit Bolsee Date: Thu, 7 May 2009 09:13:01 +0000 Subject: 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... --- .../gameengine/rasterizer/RAS_rasterizer.vcproj | 12 ++--- .../openglrasterizer/RAS_openglrasterizer.vcproj | 12 ++--- source/gameengine/Ketsji/BL_BlenderShader.cpp | 32 +++++------- source/gameengine/Ketsji/BL_BlenderShader.h | 13 ++++- source/gameengine/Ketsji/KX_BlenderMaterial.cpp | 18 +++++-- source/gameengine/Ketsji/KX_BlenderMaterial.h | 1 + source/gameengine/Ketsji/KX_GameObject.cpp | 51 +++++++++++++++--- source/gameengine/Ketsji/KX_GameObject.h | 1 + source/gameengine/Ketsji/KX_KetsjiEngine.cpp | 28 +++++----- source/gameengine/Ketsji/KX_Light.cpp | 5 +- source/gameengine/Ketsji/KX_PolygonMaterial.cpp | 15 ++++-- source/gameengine/Ketsji/KX_PythonInit.cpp | 7 +-- source/gameengine/Ketsji/KX_Scene.cpp | 2 + source/gameengine/Rasterizer/CMakeLists.txt | 1 + source/gameengine/Rasterizer/Makefile | 1 + source/gameengine/Rasterizer/RAS_BucketManager.cpp | 60 +++++++++++++++++++++- source/gameengine/Rasterizer/RAS_BucketManager.h | 1 + .../gameengine/Rasterizer/RAS_IPolygonMaterial.cpp | 3 ++ .../gameengine/Rasterizer/RAS_IPolygonMaterial.h | 1 + .../gameengine/Rasterizer/RAS_MaterialBucket.cpp | 12 ++--- source/gameengine/Rasterizer/RAS_MaterialBucket.h | 25 +++++++-- source/gameengine/Rasterizer/RAS_MeshObject.cpp | 8 ++- source/gameengine/Rasterizer/RAS_MeshObject.h | 2 +- .../Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt | 1 + .../Rasterizer/RAS_OpenGLRasterizer/Makefile | 1 + .../RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp | 2 +- .../Rasterizer/RAS_OpenGLRasterizer/SConscript | 2 +- source/gameengine/Rasterizer/SConscript | 2 +- source/gameengine/SceneGraph/SG_DList.h | 4 ++ source/gameengine/SceneGraph/SG_QList.h | 4 ++ source/gameengine/SceneGraph/SG_Spatial.cpp | 7 ++- source/gameengine/SceneGraph/SG_Spatial.h | 8 ++- source/gameengine/VideoTexture/ImageRender.cpp | 3 -- source/kernel/gen_system/GEN_HashedPtr.cpp | 9 +++- 34 files changed, 261 insertions(+), 93 deletions(-) diff --git a/projectfiles_vc9/gameengine/rasterizer/RAS_rasterizer.vcproj b/projectfiles_vc9/gameengine/rasterizer/RAS_rasterizer.vcproj index d3d35ff4826..dde8714507a 100644 --- a/projectfiles_vc9/gameengine/rasterizer/RAS_rasterizer.vcproj +++ b/projectfiles_vc9/gameengine/rasterizer/RAS_rasterizer.vcproj @@ -43,7 +43,7 @@ GetBlenderScene(); mBlendMode = GPU_BLEND_SOLID; - if(mMat) - GPU_material_from_blender(mBlenderScene, mMat); + ReloadMaterial(); } BL_BlenderShader::~BL_BlenderShader() { - if(mMat && GPU_material_from_blender(mBlenderScene, mMat)) - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + if(mGPUMat) + GPU_material_unbind(mGPUMat); } -bool BL_BlenderShader::Ok() +void BL_BlenderShader::ReloadMaterial() { - return VerifyShader(); -} - -bool BL_BlenderShader::VerifyShader() -{ - if(mMat) - return (GPU_material_from_blender(mBlenderScene, mMat) != 0); - else - return false; + mGPUMat = (mMat) ? GPU_material_from_blender(mBlenderScene, mMat) : NULL; } void BL_BlenderShader::SetProg(bool enable, double time) { if(VerifyShader()) { if(enable) - GPU_material_bind(GPU_material_from_blender(mBlenderScene, mMat), mLightLayer, mBlenderScene->lay, time); + GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time); else - GPU_material_unbind(GPU_material_from_blender(mBlenderScene, mMat)); + GPU_material_unbind(mGPUMat); } } @@ -66,7 +58,7 @@ int BL_BlenderShader::GetAttribNum() if(!VerifyShader()) return enabled; - GPU_material_vertex_attributes(GPU_material_from_blender(mBlenderScene, mMat), &attribs); + GPU_material_vertex_attributes(mGPUMat, &attribs); for(i = 0; i < attribs.totlayer; i++) if(attribs.layer[i].glindex+1 > enabled) @@ -89,7 +81,7 @@ void BL_BlenderShader::SetAttribs(RAS_IRasterizer* ras, const BL_Material *mat) if(!VerifyShader()) return; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(ras->GetDrawingMode() == RAS_IRasterizer::KX_TEXTURED) { GPU_material_vertex_attributes(gpumat, &attribs); @@ -131,7 +123,7 @@ void BL_BlenderShader::Update(const RAS_MeshSlot & ms, RAS_IRasterizer* rasty ) float obmat[4][4], viewmat[4][4], viewinvmat[4][4], obcol[4]; GPUMaterial *gpumat; - gpumat = GPU_material_from_blender(mBlenderScene, mMat); + gpumat = mGPUMat; if(!gpumat || !GPU_material_bound(gpumat)) return; diff --git a/source/gameengine/Ketsji/BL_BlenderShader.h b/source/gameengine/Ketsji/BL_BlenderShader.h index 5c1f59f94ad..9af53bfc863 100644 --- a/source/gameengine/Ketsji/BL_BlenderShader.h +++ b/source/gameengine/Ketsji/BL_BlenderShader.h @@ -32,19 +32,28 @@ private: struct Material *mMat; int mLightLayer; int mBlendMode; + GPUMaterial *mGPUMat; - bool VerifyShader(); + bool VerifyShader() + { + return (NULL != mGPUMat); + } public: BL_BlenderShader(KX_Scene *scene, struct Material *ma, int lightlayer); virtual ~BL_BlenderShader(); - bool Ok(); + bool Ok() + { + // same as VerifyShared + return (NULL != mGPUMat); + } void SetProg(bool enable, double time=0.0); int GetAttribNum(); void SetAttribs(class RAS_IRasterizer* ras, const BL_Material *mat); void Update(const class RAS_MeshSlot & ms, class RAS_IRasterizer* rasty); + void ReloadMaterial(); int GetBlendMode(); bool Equals(BL_BlenderShader *blshader); diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp index 5f08739ea14..c3c738a8183 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp @@ -152,6 +152,12 @@ Scene* KX_BlenderMaterial::GetBlenderScene() const return mScene->GetBlenderScene(); } +void KX_BlenderMaterial::ReleaseMaterial() +{ + if (mBlenderShader) + mBlenderShader->ReloadMaterial(); +} + void KX_BlenderMaterial::OnConstruction() { if (mConstructed) @@ -409,10 +415,12 @@ KX_BlenderMaterial::ActivatShaders( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } void @@ -501,10 +509,12 @@ KX_BlenderMaterial::ActivateMat( } else rasty->SetLines(false); + ActivatGLMaterials(rasty); + ActivateTexGen(rasty); } - ActivatGLMaterials(rasty); - ActivateTexGen(rasty); + //ActivatGLMaterials(rasty); + //ActivateTexGen(rasty); } bool diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.h b/source/gameengine/Ketsji/KX_BlenderMaterial.h index d763ba3ef03..52019ed2248 100644 --- a/source/gameengine/Ketsji/KX_BlenderMaterial.h +++ b/source/gameengine/Ketsji/KX_BlenderMaterial.h @@ -121,6 +121,7 @@ private: void GetMaterialRGBAColor(unsigned char *rgba) const; Material* GetBlenderMaterial() const; Scene* GetBlenderScene() const; + void ReleaseMaterial(); // message centers void setTexData( bool enable,RAS_IRasterizer *ras); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 22b9c940178..b20c0dae97b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -436,6 +436,7 @@ double* KX_GameObject::GetOpenGLMatrix() m_bIsNegativeScaling = ((scaling[0] < 0.0) ^ (scaling[1] < 0.0) ^ (scaling[2] < 0.0)) ? true : false; trans.scale(scaling[0], scaling[1], scaling[2]); trans.getValue(fl); + GetSGNode()->ClearDirty(); } return fl; } @@ -443,8 +444,27 @@ double* KX_GameObject::GetOpenGLMatrix() void KX_GameObject::AddMeshUser() { for (size_t i=0;iAddMeshUser(this); - + { + m_meshes[i]->AddMeshUser(this, &m_meshSlots); + } + // set the part of the mesh slot that never change + double* fl = GetOpenGLMatrixPtr()->getPointer(); + RAS_Deformer *deformer = GetDeformer(); + + //RAS_MeshSlot *ms; + //for(ms =static_cast(m_meshSlots.QPeek()); + // ms!=static_cast(m_meshSlots.Self()); + // ms =static_cast(ms->QPeek())) + //{ + // ms->m_OpenGLMatrix = fl; + // ms->SetDeformer(deformer); + //} + SG_QList::iterator mit(m_meshSlots); + for(mit.begin(); !mit.end(); ++mit) + { + (*mit)->m_OpenGLMatrix = fl; + (*mit)->SetDeformer(deformer); + } UpdateBuckets(false); } @@ -468,10 +488,29 @@ static void UpdateBuckets_recursive(SG_Node* node) void KX_GameObject::UpdateBuckets( bool recursive ) { if (GetSGNode()) { - double* fl = GetOpenGLMatrixPtr()->getPointer(); - - for (size_t i=0;iUpdateBuckets(this, fl, m_bUseObjectColor, m_objectColor, m_bVisible, m_bCulled); + RAS_MeshSlot *ms; + + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); + //for(ms =static_cast(m_meshSlots.QPeek()); + // ms!=static_cast(m_meshSlots.Self()); + // ms =static_cast(ms->QPeek())) + SG_QList::iterator mit(m_meshSlots); + for(mit.begin(); !mit.end(); ++mit) + { + ms = *mit; + ms->m_bObjectColor = m_bUseObjectColor; + ms->m_RGBAcolor = m_objectColor; + ms->m_bVisible = m_bVisible; + ms->m_bCulled = m_bCulled || !m_bVisible; + if (!ms->m_bCulled) + ms->m_bucket->ActivateMesh(ms); + + /* split if necessary */ +#ifdef USE_SPLIT + ms->Split(); +#endif + } if (recursive) { UpdateBuckets_recursive(GetSGNode()); diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h index bbb1b8bb360..2869404ee9b 100644 --- a/source/gameengine/Ketsji/KX_GameObject.h +++ b/source/gameengine/Ketsji/KX_GameObject.h @@ -77,6 +77,7 @@ protected: STR_String m_text; int m_layer; std::vector m_meshes; + SG_QList m_meshSlots; // head of mesh slots of this struct Object* m_pBlenderObject; struct Object* m_pBlenderGroupObject; diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp index d6747bd1ba4..e773a9571f1 100644 --- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp +++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp @@ -296,11 +296,13 @@ void KX_KetsjiEngine::RenderDome() return; KX_SceneList::iterator sceneit; - for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) - { - // do this only once per scene - (*sceneit)->UpdateMeshTransformations(); - } + + // This is now done incrementally in KX_Scene::CalculateVisibleMeshes() + //for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++) + //{ + // // do this only once per scene + // (*sceneit)->UpdateMeshTransformations(); + //} int n_renders=m_dome->GetNumberRenders();// usually 4 or 6 for (int i=0;iGetWorldInfo()); - // do this only once per scene - scene->UpdateMeshTransformations(); + // this is now done incrementatlly in KX_Scene::CalculateVisibleMeshes + //scene->UpdateMeshTransformations(); // shadow buffers RenderShadowBuffers(scene); @@ -1119,16 +1121,13 @@ void KX_KetsjiEngine::GetSceneViewport(KX_Scene *scene, KX_Camera* cam, RAS_Rect void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene) { - CListValue *objectlist = scene->GetObjectList(); + CListValue *lightlist = scene->GetLightList(); int i, drawmode; m_rendertools->SetAuxilaryClientInfo(scene); - for(i=0; iGetCount(); i++) { - KX_GameObject *gameobj = (KX_GameObject*)objectlist->GetValue(i); - - if(!gameobj->IsLight()) - continue; + for(i=0; iGetCount(); i++) { + KX_GameObject *gameobj = (KX_GameObject*)lightlist->GetValue(i); KX_LightObject *light = (KX_LightObject*)gameobj; @@ -1268,9 +1267,6 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam) m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); - //redundant, already done in Render() - //scene->UpdateMeshTransformations(); - // The following actually reschedules all vertices to be // redrawn. There is a cache between the actual rescheduling // and this call though. Visibility is imparted when this call diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 0f90bfd8a02..777a7f32629 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -102,8 +102,11 @@ void KX_LightObject::Update() { GPULamp *lamp; - if((lamp = GetGPULamp())) { + if((lamp = GetGPULamp()) != NULL && GetSGNode()) { float obmat[4][4]; + // lights don't get their openGL matrix updated, do it now + if (GetSGNode()->IsDirty()) + GetOpenGLMatrix(); double *dobmat = GetOpenGLMatrixPtr()->getPointer(); for(int i=0; i<4; i++) diff --git a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp index 918c251599e..2aa0ef921e9 100644 --- a/source/gameengine/Ketsji/KX_PolygonMaterial.cpp +++ b/source/gameengine/Ketsji/KX_PolygonMaterial.cpp @@ -172,13 +172,18 @@ void KX_PolygonMaterial::DefaultActivate(RAS_IRasterizer* rasty, TCachingInfo& c rasty->SetLines(true); else rasty->SetLines(false); + rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + rasty->SetShinyness(m_shininess); + rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + if (m_material) + rasty->SetPolygonOffset(-m_material->zoffs, 0.0); } - rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); - rasty->SetShinyness(m_shininess); - rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); - if (m_material) - rasty->SetPolygonOffset(-m_material->zoffs, 0.0); + //rasty->SetSpecularity(m_specular[0],m_specular[1],m_specular[2],m_specularity); + //rasty->SetShinyness(m_shininess); + //rasty->SetDiffuse(m_diffuse[0], m_diffuse[1],m_diffuse[2], 1.0); + //if (m_material) + // rasty->SetPolygonOffset(-m_material->zoffs, 0.0); } void KX_PolygonMaterial::GetMaterialRGBAColor(unsigned char *rgba) const diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp index 1a571633b15..57f736a6c09 100644 --- a/source/gameengine/Ketsji/KX_PythonInit.cpp +++ b/source/gameengine/Ketsji/KX_PythonInit.cpp @@ -936,16 +936,17 @@ static PyObject* gPySetGLSLMaterialSetting(PyObject*, /* display lists and GLSL materials need to be remade */ if(G.fileflags != fileflags) { + GPU_materials_free(); if(gp_KetsjiEngine) { KX_SceneList *scenes = gp_KetsjiEngine->CurrentScenes(); KX_SceneList::iterator it; for(it=scenes->begin(); it!=scenes->end(); it++) - if((*it)->GetBucketManager()) + if((*it)->GetBucketManager()) { (*it)->GetBucketManager()->ReleaseDisplayLists(); + (*it)->GetBucketManager()->ReleaseMaterials(); + } } - - GPU_materials_free(); } Py_RETURN_NONE; diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index d31d451f02e..7280071cd1d 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -488,6 +488,8 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal // this is the list of object that are send to the graphics pipeline m_objectlist->Add(newobj->AddRef()); + if (newobj->IsLight()) + m_lightlist->Add(newobj->AddRef()); newobj->AddMeshUser(); // logic cannot be replicated, until the whole hierarchy is replicated. 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 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::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::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::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& 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::iterator it; - if(m_joinSlot) return true; if(!m_bCulled) return false; -#ifdef USE_SPLIT + list::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_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 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 m_meshSlots; + list 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::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::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 = [] diff --git a/source/gameengine/SceneGraph/SG_DList.h b/source/gameengine/SceneGraph/SG_DList.h index d682be679e6..dc5afa2ee99 100644 --- a/source/gameengine/SceneGraph/SG_DList.h +++ b/source/gameengine/SceneGraph/SG_DList.h @@ -83,6 +83,10 @@ public: { m_flink = m_blink = this; } + SG_DList(const SG_DList& other) + { + m_flink = m_blink = this; + } virtual ~SG_DList() { Delink(); diff --git a/source/gameengine/SceneGraph/SG_QList.h b/source/gameengine/SceneGraph/SG_QList.h index efaa613bbb9..4a254ac36a4 100644 --- a/source/gameengine/SceneGraph/SG_QList.h +++ b/source/gameengine/SceneGraph/SG_QList.h @@ -84,6 +84,10 @@ public: { m_fqlink = m_bqlink = this; } + SG_QList(const SG_QList& other) : SG_DList() + { + m_fqlink = m_bqlink = this; + } virtual ~SG_QList() { QDelink(); diff --git a/source/gameengine/SceneGraph/SG_Spatial.cpp b/source/gameengine/SceneGraph/SG_Spatial.cpp index b79d4bac91a..5a47f07f573 100644 --- a/source/gameengine/SceneGraph/SG_Spatial.cpp +++ b/source/gameengine/SceneGraph/SG_Spatial.cpp @@ -56,7 +56,8 @@ SG_Spatial( m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)), m_radius(1.0), - m_modified(false) + m_modified(false), + m_ogldirty(false) { } @@ -76,7 +77,9 @@ SG_Spatial( m_parent_relation(NULL), m_bbox(other.m_bbox), - m_radius(other.m_radius) + m_radius(other.m_radius), + m_modified(false), + m_ogldirty(false) { // duplicate the parent relation for this object m_parent_relation = other.m_parent_relation->NewCopy(); diff --git a/source/gameengine/SceneGraph/SG_Spatial.h b/source/gameengine/SceneGraph/SG_Spatial.h index eb1e87fbf19..d1fc95cceac 100644 --- a/source/gameengine/SceneGraph/SG_Spatial.h +++ b/source/gameengine/SceneGraph/SG_Spatial.h @@ -63,19 +63,24 @@ protected: SG_BBox m_bbox; MT_Scalar m_radius; bool m_modified; + bool m_ogldirty; // true if the openGL matrix for this object must be recomputed public: inline void ClearModified() { m_modified = false; + m_ogldirty = true; } inline void SetModified() { m_modified = true; ActivateScheduleUpdateCallback(); } - + inline void ClearDirty() + { + m_ogldirty = false; + } /** * Define the realtionship this node has with it's parent * node. You should pass an unshared instance of an SG_ParentRelation @@ -233,6 +238,7 @@ public: MT_Scalar Radius() const { return m_radius; } void SetRadius(MT_Scalar radius) { m_radius = radius; } bool IsModified() { return m_modified; } + bool IsDirty() { return m_ogldirty; } protected: friend class SG_Controller; diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 1e3a84c1efb..db4461325d8 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -255,9 +255,6 @@ void ImageRender::Render() // restore the stereo mode now that the matrix is computed m_rasterizer->SetStereoMode(stereomode); - // do not update the mesh transform, we don't want to do it more than once per frame - //m_scene->UpdateMeshTransformations(); - m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); m_scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); diff --git a/source/kernel/gen_system/GEN_HashedPtr.cpp b/source/kernel/gen_system/GEN_HashedPtr.cpp index 6dbed1fb7a8..ff9de465a34 100644 --- a/source/kernel/gen_system/GEN_HashedPtr.cpp +++ b/source/kernel/gen_system/GEN_HashedPtr.cpp @@ -40,11 +40,12 @@ // is a 32-bit integer, use all the bits of the pointer as long // as possible. // - +#if 1 unsigned int GEN_Hash(void * inDWord) { uintptr_t key = (uintptr_t)inDWord; - +#if 0 + // this is way too complicated key += ~(key << 16); key ^= (key >> 5); key += (key << 3); @@ -53,4 +54,8 @@ unsigned int GEN_Hash(void * inDWord) key ^= (key >> 17); return (unsigned int)(key & 0xffffffff); +#else + return (unsigned int)(key ^ (key>>4)); +#endif } +#endif \ No newline at end of file -- cgit v1.2.3