Skip to content

Commit

Permalink
UPBGE: Restore UpdateIPO with mutex.
Browse files Browse the repository at this point in the history
Previously the game object sg controllers were update after the action
were updated, this behaviour is the only one safe, but the update of the
IPO was costing a lot of time because we iterate again over all the action
from the action manager and that this operation was not parallelized.

The update IPO of an object is updating the conroller from the scene graph
node of this object and updating the spacial data of this node (position…)
The spcial data update is proceeded for the children of the node too.

To parallelize this operation we have to make sure that nodes of the familly
are not updated in the same time. The familly is the shared instance between
all the nodes from the root parent node included.
This familly is the new SG_Familly class which is for the moment only
containing a mutex for the IPO update, this mutex is bound in two news
functions used only for parallelizme: SG_Node::UpdateWorldDataThread and
SG_Node::SetSimulatedTimeThread.

Every nodes are instanciated with a new familly and reuse an existing familly
when they are set to child of an other node.

The familly mutex is not the only mutex used, there are two other for schedule
list update and node transform. The last one is for the bullet implementation
which is modifying a AABB manager.

Now that the update IPO can be parallelized the call of BL_Action::UpdateIPO
is moved into a second loop in BL_ActionManager::Update.

The function BL_Action::UpdateIPO is also optimized. It use a flag named
m_requestIpo set to true in BL_Action::Update when the action is not finished,
not redundant and applied to the object.

In KX_Scene the task pool is created only once to avoid spending time recreating
it. It is stored into m_animationPool.

Fix issue #388.
  • Loading branch information
panzergame committed Feb 25, 2017
1 parent d5ed120 commit 2b3405a
Show file tree
Hide file tree
Showing 16 changed files with 248 additions and 49 deletions.
18 changes: 14 additions & 4 deletions source/gameengine/Ketsji/BL_Action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
m_ipo_flags(0),
m_done(true),
m_appliedToObject(true),
m_requestIpo(false),
m_calc_localtime(true),
m_prevUpdate(-1.0f)
{
Expand Down Expand Up @@ -258,6 +259,7 @@ bool BL_Action::Play(const std::string& name,

m_done = false;
m_appliedToObject = false;
m_requestIpo = false;

m_prevUpdate = -1.0f;

Expand Down Expand Up @@ -378,7 +380,7 @@ void BL_Action::Update(float curtime, bool applyToObject)
/* Don't bother if we're done with the animation and if the animation was already applied to the object.
* of if the animation made a double update for the same time and that it was applied to the object.
*/
if ((m_done && m_appliedToObject) || (m_prevUpdate == curtime && m_appliedToObject)) {
if ((m_done || m_prevUpdate == curtime) && m_appliedToObject) {
return;
}
m_prevUpdate = curtime;
Expand Down Expand Up @@ -424,6 +426,8 @@ void BL_Action::Update(float curtime, bool applyToObject)
return;
}

m_requestIpo = true;

if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
{
BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
Expand Down Expand Up @@ -499,9 +503,15 @@ void BL_Action::Update(float curtime, bool applyToObject)

void BL_Action::UpdateIPOs()
{
/* This function does nothing if the scene graph controllers are already removed
* by ClearControllerList. */
m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD);
if (m_sg_contr_list.size() == 0) {
// Nothing to update or remove.
return;
}

if (m_requestIpo) {
m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD);
m_requestIpo = false;
}

// If the action is done we can remove its scene graph IPO controller.
if (m_done) {
Expand Down
3 changes: 3 additions & 0 deletions source/gameengine/Ketsji/BL_Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ class BL_Action
* to the object.
*/
bool m_appliedToObject;

/// Set to true when the action was updated and applied. Back to false in the IPO update (UpdateIPO).
bool m_requestIpo;
bool m_calc_localtime;

// The last update time to avoid double animation update.
Expand Down
12 changes: 4 additions & 8 deletions source/gameengine/Ketsji/BL_ActionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,11 @@ bool BL_ActionManager::IsActionDone(short layer)

void BL_ActionManager::Update(float curtime, bool applyToObject)
{
BL_ActionMap::iterator it;
for (it = m_layers.begin(); it != m_layers.end(); ++it) {
it->second->Update(curtime, applyToObject);
for (const auto& pair : m_layers) {
pair.second->Update(curtime, applyToObject);
}
}

void BL_ActionManager::UpdateIPOs()
{
for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end(); ++it) {
it->second->UpdateIPOs();
for (const auto& pair : m_layers) {
pair.second->UpdateIPOs();
}
}
5 changes: 0 additions & 5 deletions source/gameengine/Ketsji/BL_ActionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,6 @@ class BL_ActionManager
*/
void Update(float curtime, bool applyToObject);

/**
* Update object IPOs (note: not thread-safe!)
*/
void UpdateIPOs();

#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ActionManager")
#endif
Expand Down
11 changes: 3 additions & 8 deletions source/gameengine/Ketsji/KX_GameObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "SG_Controller.h"
#include "PHY_IGraphicController.h"
#include "SG_Node.h"
#include "SG_Familly.h"
#include "KX_ClientObjectInfo.h"
#include "RAS_BucketManager.h"
#include "KX_RayCast.h"
Expand Down Expand Up @@ -476,11 +477,6 @@ void KX_GameObject::UpdateActionManager(float curtime, bool applyToObject)
GetActionManager()->Update(curtime, applyToObject);
}

void KX_GameObject::UpdateActionIPOs()
{
GetActionManager()->UpdateIPOs();
}

float KX_GameObject::GetActionFrame(short layer)
{
return GetActionManager()->GetActionFrame(layer);
Expand Down Expand Up @@ -887,9 +883,8 @@ void KX_GameObject::UpdateIPO(float curframetime,
bool recurse)
{
// just the 'normal' update procedure.
GetSGNode()->SetSimulatedTime(curframetime,recurse);
GetSGNode()->UpdateWorldData(curframetime);
UpdateTransform();
GetSGNode()->SetSimulatedTimeThread(curframetime,recurse);
GetSGNode()->UpdateWorldDataThread(curframetime);
}

bool
Expand Down
6 changes: 0 additions & 6 deletions source/gameengine/Ketsji/KX_GameObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,6 @@ class KX_GameObject : public SCA_IObject
*/
void UpdateActionManager(float curtime, bool applyObject);

/**
* Have the action manager update IPOs
* note: not thread-safe!
*/
void UpdateActionIPOs();

/*********************************
* End Animation API
*********************************/
Expand Down
1 change: 0 additions & 1 deletion source/gameengine/Ketsji/KX_KetsjiEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,6 @@ void KX_KetsjiEngine::EndFrame()

bool KX_KetsjiEngine::NextFrame()
{

m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);

/*
Expand Down
22 changes: 12 additions & 10 deletions source/gameengine/Ketsji/KX_Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ KX_Scene::KX_Scene(SCA_IInputDevice *inputDevice,
default:
m_obstacleSimulation = nullptr;
}


m_animationPool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &m_animationPoolData);

#ifdef WITH_PYTHON
m_attr_dict = nullptr;

Expand Down Expand Up @@ -240,6 +242,10 @@ KX_Scene::~KX_Scene()
if (m_obstacleSimulation)
delete m_obstacleSimulation;

if (m_animationPool) {
BLI_task_pool_free(m_animationPool);
}

if (m_objectlist)
m_objectlist->Release();

Expand Down Expand Up @@ -1547,7 +1553,8 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t
KX_GameObject *gameobj, *child, *parent;
CListValue *children;
bool needs_update;
double curtime = *(double*)BLI_task_pool_userdata(pool);
KX_Scene::AnimationPoolData *data = (KX_Scene::AnimationPoolData *)BLI_task_pool_userdata(pool);
double curtime = data->curtime;

gameobj = (KX_GameObject*)taskdata;

Expand Down Expand Up @@ -1611,18 +1618,13 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t

void KX_Scene::UpdateAnimations(double curtime)
{
TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime);
m_animationPoolData.curtime = curtime;

for (CListValue::iterator<KX_GameObject> it = m_animatedlist->GetBegin(), end = m_animatedlist->GetEnd(); it != end; ++it) {
BLI_task_pool_push(pool, update_anim_thread_func, *it, false, TASK_PRIORITY_LOW);
BLI_task_pool_push(m_animationPool, update_anim_thread_func, *it, false, TASK_PRIORITY_LOW);
}

BLI_task_pool_work_and_wait(pool);
BLI_task_pool_free(pool);

for (CListValue::iterator<KX_GameObject> it = m_animatedlist->GetBegin(), end = m_animatedlist->GetEnd(); it != end; ++it) {
(*it)->UpdateActionIPOs();
}
BLI_task_pool_work_and_wait(m_animationPool);
}

void KX_Scene::LogicUpdateFrame(double curtime, bool frame)
Expand Down
9 changes: 9 additions & 0 deletions source/gameengine/Ketsji/KX_Scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class btCollisionShape;
class KX_BlenderSceneConverter;
struct KX_ClientObjectInfo;
class KX_ObstacleSimulation;
struct TaskPool;

#ifdef WITH_CXX_GUARDEDALLOC
#include "MEM_guardedalloc.h"
Expand All @@ -109,6 +110,11 @@ class KX_Scene : public CValue, public SCA_IScene
MAX_DRAW_CALLBACK
};

struct AnimationPoolData
{
double curtime;
};

private:
Py_Header

Expand Down Expand Up @@ -298,6 +304,9 @@ class KX_Scene : public CValue, public SCA_IScene

KX_ObstacleSimulation* m_obstacleSimulation;

AnimationPoolData m_animationPoolData;
TaskPool *m_animationPool;

/**
* LOD Hysteresis settings
*/
Expand Down
4 changes: 2 additions & 2 deletions source/gameengine/Launcher/LA_Launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ void LA_Launcher::InitEngine()

// Create the ketsjiengine.
m_ketsjiEngine = new KX_KetsjiEngine(m_kxsystem);

KX_SetActiveEngine(m_ketsjiEngine);

// Set the devices.
m_ketsjiEngine->SetInputDevice(m_inputDevice);
m_ketsjiEngine->SetCanvas(m_canvas);
Expand Down Expand Up @@ -270,7 +271,6 @@ void LA_Launcher::InitEngine()
m_networkMessageManager);

KX_SetActiveScene(m_kxStartScene);
KX_SetActiveEngine(m_ketsjiEngine);

#ifdef WITH_PYTHON
// Some python things.
Expand Down
3 changes: 3 additions & 0 deletions source/gameengine/SceneGraph/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

set(INC
.
../Common
../../blender/blenlib
)

Expand All @@ -35,11 +36,13 @@ set(INC_SYS
set(SRC
SG_BBox.cpp
SG_Controller.cpp
SG_Familly.cpp
SG_Node.cpp

SG_BBox.h
SG_Controller.h
SG_DList.h
SG_Familly.h
SG_Node.h
SG_ParentRelation.h
SG_QList.h
Expand Down
37 changes: 37 additions & 0 deletions source/gameengine/SceneGraph/SG_Familly.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/

/** \file gameengine/SceneGraph/SG_Familly.cpp
* \ingroup bgesg
*/

#include "SG_Familly.h"

CM_ThreadSpinLock& SG_Familly::GetMutex()
{
return m_mutex;
}
53 changes: 53 additions & 0 deletions source/gameengine/SceneGraph/SG_Familly.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Implementationclass to derive controllers from
*
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/

/** \file SG_Familly.h
* \ingroup bgesg
*/

#ifndef __SG_FAMILLY_H__
#define __SG_FAMILLY_H__

#include "CM_Thread.h"

class SG_Familly
{
private:
CM_ThreadSpinLock m_mutex;

public:
SG_Familly() = default;
~SG_Familly() = default;

CM_ThreadSpinLock& GetMutex();

};

#endif /* __SG_FAMILLY_H__ */
Loading

0 comments on commit 2b3405a

Please sign in to comment.