BGE: fix memleaks.

SCA_RandomActuator: The random generator was shared between replicas and not deleted. Added ref counting between replicas to allow deletion at the end.
KX_Camera: The scenegraph node was not deleted for temporary cameras (ImageMirror and shadow), causing 500 bytes leak per frame and per shadow light.
KX_GameActuator: Global dictionary buffer was not deleted after saving.
KX_MotionState: The motion state for compound child was not deleted
KX_ReplaceMeshActuator: The mesh was unnecessarily converted for each actuator and not deleted, causing large memleak.

After these fix, YoFrankie runs without memleak.
This commit is contained in:
Benoit Bolsee 2009-05-23 14:46:43 +00:00
parent 6d8d7cd768
commit 5441323dca
20 changed files with 85 additions and 43 deletions

@ -729,6 +729,8 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
bool skinMesh = false; bool skinMesh = false;
int lightlayer = blenderobj->lay; int lightlayer = blenderobj->lay;
if ((meshobj = converter->FindGameMesh(mesh/*, ob->lay*/)) != NULL)
return meshobj;
// Get DerivedMesh data // Get DerivedMesh data
DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj); DerivedMesh *dm = CDDM_from_mesh(mesh, blenderobj);
@ -1043,7 +1045,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
// pre calculate texture generation // pre calculate texture generation
for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial(); for(list<RAS_MeshMaterial>::iterator mit = meshobj->GetFirstMaterial();
mit != meshobj->GetLastMaterial(); ++ mit) { mit != meshobj->GetLastMaterial(); ++ mit) {
mit->m_bucket->GetPolyMaterial()->OnConstruction(); mit->m_bucket->GetPolyMaterial()->OnConstruction(lightlayer);
} }
if (layers) if (layers)
@ -1057,6 +1059,7 @@ RAS_MeshObject* BL_ConvertMesh(Mesh* mesh, Object* blenderobj, RAS_IRenderTools*
delete kx_blmat; delete kx_blmat;
if (kx_polymat) if (kx_polymat)
delete kx_polymat; delete kx_polymat;
converter->RegisterGameMesh(meshobj, mesh);
return meshobj; return meshobj;
} }
@ -1712,14 +1715,9 @@ static KX_GameObject *gameobject_from_blenderobject(
case OB_MESH: case OB_MESH:
{ {
Mesh* mesh = static_cast<Mesh*>(ob->data); Mesh* mesh = static_cast<Mesh*>(ob->data);
RAS_MeshObject* meshobj = converter->FindGameMesh(mesh, ob->lay);
float center[3], extents[3]; float center[3], extents[3];
float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents); float radius = my_boundbox_mesh((Mesh*) ob->data, center, extents);
RAS_MeshObject* meshobj = BL_ConvertMesh(mesh,ob,rendertools,kxscene,converter);
if (!meshobj) {
meshobj = BL_ConvertMesh(mesh,ob,rendertools,kxscene,converter);
converter->RegisterGameMesh(meshobj, mesh);
}
// needed for python scripting // needed for python scripting
kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj); kxscene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);

@ -550,12 +550,12 @@ void KX_BlenderSceneConverter::RegisterGameMesh(
RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh( RAS_MeshObject *KX_BlenderSceneConverter::FindGameMesh(
struct Mesh *for_blendermesh, struct Mesh *for_blendermesh/*,
unsigned int onlayer) unsigned int onlayer*/)
{ {
RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)]; RAS_MeshObject** meshp = m_map_mesh_to_gamemesh[CHashedPtr(for_blendermesh)];
if (meshp && onlayer==(*meshp)->GetLightLayer()) { if (meshp/* && onlayer==(*meshp)->GetLightLayer()*/) {
return *meshp; return *meshp;
} else { } else {
return NULL; return NULL;

@ -115,7 +115,7 @@ public:
struct Object *FindBlenderObject(KX_GameObject *for_gameobject); struct Object *FindBlenderObject(KX_GameObject *for_gameobject);
void RegisterGameMesh(RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh); void RegisterGameMesh(RAS_MeshObject *gamemesh, struct Mesh *for_blendermesh);
RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh, unsigned int onlayer); RAS_MeshObject *FindGameMesh(struct Mesh *for_blendermesh/*, unsigned int onlayer*/);
// void RegisterSumoShape(DT_ShapeHandle shape, RAS_MeshObject *for_gamemesh); // void RegisterSumoShape(DT_ShapeHandle shape, RAS_MeshObject *for_gamemesh);
// DT_ShapeHandle FindSumoShape(RAS_MeshObject *for_gamemesh); // DT_ShapeHandle FindSumoShape(RAS_MeshObject *for_gamemesh);

@ -59,6 +59,7 @@
SCA_RandomNumberGenerator::SCA_RandomNumberGenerator(long seed) { SCA_RandomNumberGenerator::SCA_RandomNumberGenerator(long seed) {
// int mti = N + 1; /*unused*/ // int mti = N + 1; /*unused*/
m_seed = seed; m_seed = seed;
m_refcount = 1;
SetStartVector(); SetStartVector();
} }

@ -36,6 +36,9 @@
class SCA_RandomNumberGenerator { class SCA_RandomNumberGenerator {
/* reference counted for memleak */
int m_refcount;
/** base seed */ /** base seed */
long m_seed; long m_seed;
@ -56,6 +59,16 @@ class SCA_RandomNumberGenerator {
float DrawFloat(); float DrawFloat();
long GetSeed(); long GetSeed();
void SetSeed(long newseed); void SetSeed(long newseed);
SCA_RandomNumberGenerator* AddRef()
{
++m_refcount;
return this;
}
void Release()
{
if (--m_refcount == 0)
delete this;
}
}; };
#endif /* __KX_RANDOMNUMBERGENERATOR */ #endif /* __KX_RANDOMNUMBERGENERATOR */

@ -50,7 +50,6 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr,
PyTypeObject* T) PyTypeObject* T)
: SCA_ISensor(gameobj,eventmgr, T) : SCA_ISensor(gameobj,eventmgr, T)
{ {
// m_basegenerator is never deleted => memory leak
m_basegenerator = new SCA_RandomNumberGenerator(startseed); m_basegenerator = new SCA_RandomNumberGenerator(startseed);
Init(); Init();
} }
@ -59,7 +58,7 @@ SCA_RandomSensor::SCA_RandomSensor(SCA_EventManager* eventmgr,
SCA_RandomSensor::~SCA_RandomSensor() SCA_RandomSensor::~SCA_RandomSensor()
{ {
/* Nothing to be done here. */ m_basegenerator->Release();
} }
void SCA_RandomSensor::Init() void SCA_RandomSensor::Init()
@ -74,13 +73,18 @@ void SCA_RandomSensor::Init()
CValue* SCA_RandomSensor::GetReplica() CValue* SCA_RandomSensor::GetReplica()
{ {
CValue* replica = new SCA_RandomSensor(*this); CValue* replica = new SCA_RandomSensor(*this);
// replication copies m_basegenerator pointer => share same generator
// this will copy properties and so on... // this will copy properties and so on...
replica->ProcessReplica(); replica->ProcessReplica();
return replica; return replica;
} }
void SCA_RandomSensor::ProcessReplica()
{
SCA_ISensor::ProcessReplica();
// increment reference count so that we can release the generator at this end
m_basegenerator->AddRef();
}
bool SCA_RandomSensor::IsPositiveTrigger() bool SCA_RandomSensor::IsPositiveTrigger()

@ -52,6 +52,7 @@ public:
PyTypeObject* T=&Type); PyTypeObject* T=&Type);
virtual ~SCA_RandomSensor(); virtual ~SCA_RandomSensor();
virtual CValue* GetReplica(); virtual CValue* GetReplica();
virtual void ProcessReplica();
virtual bool Evaluate(); virtual bool Evaluate();
virtual bool IsPositiveTrigger(); virtual bool IsPositiveTrigger();
virtual void Init(); virtual void Init();

@ -158,14 +158,14 @@ void KX_BlenderMaterial::ReleaseMaterial()
mBlenderShader->ReloadMaterial(); mBlenderShader->ReloadMaterial();
} }
void KX_BlenderMaterial::OnConstruction() void KX_BlenderMaterial::OnConstruction(int layer)
{ {
if (mConstructed) if (mConstructed)
// when material are reused between objects // when material are reused between objects
return; return;
if(mMaterial->glslmat) if(mMaterial->glslmat)
SetBlenderGLSLShader(); SetBlenderGLSLShader(layer);
// for each unique material... // for each unique material...
int i; int i;
@ -902,10 +902,10 @@ KX_PYMETHODDEF_DOC( KX_BlenderMaterial, getShader , "getShader()")
} }
void KX_BlenderMaterial::SetBlenderGLSLShader(void) void KX_BlenderMaterial::SetBlenderGLSLShader(int layer)
{ {
if(!mBlenderShader) if(!mBlenderShader)
mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, m_lightlayer); mBlenderShader = new BL_BlenderShader(mScene, mMaterial->material, layer);
if(!mBlenderShader->Ok()) { if(!mBlenderShader->Ok()) {
delete mBlenderShader; delete mBlenderShader;

@ -97,7 +97,7 @@ public:
// -------------------------------- // --------------------------------
// pre calculate to avoid pops/lag at startup // pre calculate to avoid pops/lag at startup
virtual void OnConstruction( ); virtual void OnConstruction(int layer);
static void EndFrame(); static void EndFrame();
@ -112,7 +112,7 @@ private:
bool mModified; bool mModified;
bool mConstructed; // if false, don't clean on exit bool mConstructed; // if false, don't clean on exit
void SetBlenderGLSLShader(); void SetBlenderGLSLShader(int layer);
void ActivatGLMaterials( RAS_IRasterizer* rasty )const; void ActivatGLMaterials( RAS_IRasterizer* rasty )const;
void ActivateTexGen( RAS_IRasterizer *ras ) const; void ActivateTexGen( RAS_IRasterizer *ras ) const;

@ -42,6 +42,7 @@ KX_Camera::KX_Camera(void* sgReplicationInfo,
SG_Callbacks callbacks, SG_Callbacks callbacks,
const RAS_CameraData& camdata, const RAS_CameraData& camdata,
bool frustum_culling, bool frustum_culling,
bool delete_node,
PyTypeObject *T) PyTypeObject *T)
: :
KX_GameObject(sgReplicationInfo,callbacks,T), KX_GameObject(sgReplicationInfo,callbacks,T),
@ -50,7 +51,8 @@ KX_Camera::KX_Camera(void* sgReplicationInfo,
m_normalized(false), m_normalized(false),
m_frustum_culling(frustum_culling), m_frustum_culling(frustum_culling),
m_set_projection_matrix(false), m_set_projection_matrix(false),
m_set_frustum_center(false) m_set_frustum_center(false),
m_delete_node(delete_node)
{ {
// setting a name would be nice... // setting a name would be nice...
m_name = "cam"; m_name = "cam";
@ -64,6 +66,12 @@ KX_Camera::KX_Camera(void* sgReplicationInfo,
KX_Camera::~KX_Camera() KX_Camera::~KX_Camera()
{ {
if (m_delete_node && m_pSGNode)
{
// for shadow camera, avoids memleak
delete m_pSGNode;
m_pSGNode = NULL;
}
} }
@ -77,6 +85,13 @@ CValue* KX_Camera::GetReplica()
return replica; return replica;
} }
void KX_Camera::ProcessReplica()
{
KX_GameObject::ProcessReplica();
// replicated camera are always registered in the scene
m_delete_node = false;
}
MT_Transform KX_Camera::GetWorldToCamera() const MT_Transform KX_Camera::GetWorldToCamera() const
{ {
MT_Transform camtrans; MT_Transform camtrans;

@ -112,6 +112,11 @@ protected:
MT_Scalar m_frustum_radius; MT_Scalar m_frustum_radius;
bool m_set_frustum_center; bool m_set_frustum_center;
/**
* whether the camera should delete the node itself (only for shadow camera)
*/
bool m_delete_node;
/** /**
* Extracts the camera clip frames from the projection and world-to-camera matrices. * Extracts the camera clip frames from the projection and world-to-camera matrices.
*/ */
@ -138,7 +143,7 @@ public:
enum { INSIDE, INTERSECT, OUTSIDE } ; enum { INSIDE, INTERSECT, OUTSIDE } ;
KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, PyTypeObject *T = &Type); KX_Camera(void* sgReplicationInfo,SG_Callbacks callbacks,const RAS_CameraData& camdata, bool frustum_culling = true, bool delete_node = false, PyTypeObject *T = &Type);
virtual ~KX_Camera(); virtual ~KX_Camera();
/** /**
@ -149,6 +154,7 @@ public:
virtual CValue* virtual CValue*
GetReplica( GetReplica(
); );
virtual void ProcessReplica();
MT_Transform GetWorldToCamera() const; MT_Transform GetWorldToCamera() const;
MT_Transform GetCameraToWorld() const; MT_Transform GetCameraToWorld() const;

@ -980,6 +980,8 @@ void KX_ConvertBulletObject( class KX_GameObject* gameobj,
compoundShape->calculateLocalInertia(mass,localInertia); compoundShape->calculateLocalInertia(mass,localInertia);
rigidbody->setMassProps(mass,localInertia); rigidbody->setMassProps(mass,localInertia);
} }
// delete motionstate as it's not used
delete motionstate;
return; return;
} }

@ -149,6 +149,8 @@ bool KX_GameActuator::Update()
} else { } else {
printf("Warning: could not create marshal buffer\n"); printf("Warning: could not create marshal buffer\n");
} }
if (marshal_buffer)
delete [] marshal_buffer;
} }
break; break;
} }

@ -1142,7 +1142,7 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) { if(m_drawingmode == RAS_IRasterizer::KX_TEXTURED && light->HasShadowBuffer()) {
/* make temporary camera */ /* make temporary camera */
RAS_CameraData camdata = RAS_CameraData(); RAS_CameraData camdata = RAS_CameraData();
KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, false); KX_Camera *cam = new KX_Camera(scene, scene->m_callbacks, camdata, true, true);
cam->SetName("__shadow__cam__"); cam->SetName("__shadow__cam__");
MT_Transform camtrans; MT_Transform camtrans;

@ -220,7 +220,7 @@ PyAttributeDef KX_PolygonMaterial::Attributes[] = {
KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep), KX_PYATTRIBUTE_INT_RW("tilexrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tilexrep),
KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep), KX_PYATTRIBUTE_INT_RW("tileyrep", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_tileyrep),
KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode), KX_PYATTRIBUTE_INT_RW("drawingmode", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_drawingmode),
KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer), //KX_PYATTRIBUTE_INT_RW("lightlayer", INT_MIN, INT_MAX, true, KX_PolygonMaterial, m_lightlayer),
KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha), KX_PYATTRIBUTE_BOOL_RW("transparent", KX_PolygonMaterial, m_alpha),
KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort), KX_PYATTRIBUTE_BOOL_RW("zsort", KX_PolygonMaterial, m_zsort),

@ -59,7 +59,7 @@ void RAS_IPolyMaterial::Initialize(
m_transp = transp; m_transp = transp;
m_alpha = alpha; m_alpha = alpha;
m_zsort = zsort; m_zsort = zsort;
m_lightlayer = lightlayer; //m_lightlayer = lightlayer;
m_polymatid = m_newpolymatid++; m_polymatid = m_newpolymatid++;
m_flag = 0; m_flag = 0;
m_multimode = 0; m_multimode = 0;
@ -80,7 +80,7 @@ RAS_IPolyMaterial::RAS_IPolyMaterial()
m_transp(0), m_transp(0),
m_alpha(false), m_alpha(false),
m_zsort(false), m_zsort(false),
m_lightlayer(0), //m_lightlayer(0),
m_polymatid(0), m_polymatid(0),
m_flag(0), m_flag(0),
m_multimode(0) m_multimode(0)
@ -112,7 +112,7 @@ RAS_IPolyMaterial::RAS_IPolyMaterial(const STR_String& texname,
m_transp(transp), m_transp(transp),
m_alpha(alpha), m_alpha(alpha),
m_zsort(zsort), m_zsort(zsort),
m_lightlayer(lightlayer), //m_lightlayer(lightlayer),
m_polymatid(m_newpolymatid++), m_polymatid(m_newpolymatid++),
m_flag(0), m_flag(0),
m_multimode(0) m_multimode(0)
@ -172,10 +172,10 @@ bool RAS_IPolyMaterial::Less(const RAS_IPolyMaterial& rhs) const
return m_polymatid < rhs.m_polymatid; return m_polymatid < rhs.m_polymatid;
} }
int RAS_IPolyMaterial::GetLightLayer() const //int RAS_IPolyMaterial::GetLightLayer() const
{ //{
return m_lightlayer; // return m_lightlayer;
} //}
bool RAS_IPolyMaterial::IsAlpha() const bool RAS_IPolyMaterial::IsAlpha() const
{ {

@ -73,7 +73,7 @@ protected:
int m_transp; int m_transp;
bool m_alpha; bool m_alpha;
bool m_zsort; bool m_zsort;
int m_lightlayer; //int m_lightlayer;
int m_materialindex; int m_materialindex;
unsigned int m_polymatid; unsigned int m_polymatid;
@ -147,7 +147,7 @@ public:
virtual bool Equals(const RAS_IPolyMaterial& lhs) const; virtual bool Equals(const RAS_IPolyMaterial& lhs) const;
bool Less(const RAS_IPolyMaterial& rhs) const; bool Less(const RAS_IPolyMaterial& rhs) const;
int GetLightLayer() const; //int GetLightLayer() const;
bool IsAlpha() const; bool IsAlpha() const;
bool IsZSort() const; bool IsZSort() const;
unsigned int hash() const; unsigned int hash() const;
@ -167,7 +167,7 @@ public:
/* /*
* PreCalculate texture gen * PreCalculate texture gen
*/ */
virtual void OnConstruction(){} virtual void OnConstruction(int layer){}
}; };
inline bool operator ==( const RAS_IPolyMaterial & rhs,const RAS_IPolyMaterial & lhs) inline bool operator ==( const RAS_IPolyMaterial & rhs,const RAS_IPolyMaterial & lhs)

@ -91,7 +91,7 @@ struct RAS_MeshObject::fronttoback
STR_String RAS_MeshObject::s_emptyname = ""; STR_String RAS_MeshObject::s_emptyname = "";
RAS_MeshObject::RAS_MeshObject(Mesh* mesh, int lightlayer) RAS_MeshObject::RAS_MeshObject(Mesh* mesh, int lightlayer)
: m_lightlayer(lightlayer), : //m_lightlayer(lightlayer),
m_bModified(true), m_bModified(true),
m_bMeshModified(true), m_bMeshModified(true),
m_mesh(mesh), m_mesh(mesh),
@ -112,10 +112,10 @@ bool RAS_MeshObject::MeshModified()
return m_bMeshModified; return m_bMeshModified;
} }
unsigned int RAS_MeshObject::GetLightLayer() //unsigned int RAS_MeshObject::GetLightLayer()
{ //{
return m_lightlayer; // return m_lightlayer;
} //}

@ -54,7 +54,7 @@ class RAS_MeshObject
{ {
private: private:
unsigned int m_debugcolor; unsigned int m_debugcolor;
int m_lightlayer; //int m_lightlayer;
bool m_bModified; bool m_bModified;
bool m_bMeshModified; bool m_bMeshModified;
@ -94,7 +94,7 @@ public:
list<RAS_MeshMaterial>::iterator GetFirstMaterial(); list<RAS_MeshMaterial>::iterator GetFirstMaterial();
list<RAS_MeshMaterial>::iterator GetLastMaterial(); list<RAS_MeshMaterial>::iterator GetLastMaterial();
unsigned int GetLightLayer(); //unsigned int GetLightLayer();
/* name */ /* name */
void SetName(const char *name); void SetName(const char *name);

@ -561,8 +561,8 @@ ImageRender::ImageRender (KX_Scene * scene, KX_GameObject * observer, KX_GameObj
float yaxis[3] = {0.f, 1.f, 0.f}; float yaxis[3] = {0.f, 1.f, 0.f};
float mirrorMat[3][3]; float mirrorMat[3][3];
float left, right, top, bottom, back; float left, right, top, bottom, back;
// make sure this camera will delete its node
m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata); m_camera= new KX_Camera(scene, KX_Scene::m_callbacks, camdata, true, true);
m_camera->SetName("__mirror__cam__"); m_camera->SetName("__mirror__cam__");
// don't add the camera to the scene object list, it doesn't need to be accessible // don't add the camera to the scene object list, it doesn't need to be accessible
m_owncamera = true; m_owncamera = true;