Skip to content

Commit 2b3405a

Browse files
committed
UPBGE: Restore UpdateIPO with mutex.
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.
1 parent d5ed120 commit 2b3405a

16 files changed

+248
-49
lines changed

source/gameengine/Ketsji/BL_Action.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ BL_Action::BL_Action(class KX_GameObject* gameobj)
7777
m_ipo_flags(0),
7878
m_done(true),
7979
m_appliedToObject(true),
80+
m_requestIpo(false),
8081
m_calc_localtime(true),
8182
m_prevUpdate(-1.0f)
8283
{
@@ -258,6 +259,7 @@ bool BL_Action::Play(const std::string& name,
258259

259260
m_done = false;
260261
m_appliedToObject = false;
262+
m_requestIpo = false;
261263

262264
m_prevUpdate = -1.0f;
263265

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

429+
m_requestIpo = true;
430+
427431
if (m_obj->GetGameObjectType() == SCA_IObject::OBJ_ARMATURE)
428432
{
429433
BL_ArmatureObject *obj = (BL_ArmatureObject*)m_obj;
@@ -499,9 +503,15 @@ void BL_Action::Update(float curtime, bool applyToObject)
499503

500504
void BL_Action::UpdateIPOs()
501505
{
502-
/* This function does nothing if the scene graph controllers are already removed
503-
* by ClearControllerList. */
504-
m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD);
506+
if (m_sg_contr_list.size() == 0) {
507+
// Nothing to update or remove.
508+
return;
509+
}
510+
511+
if (m_requestIpo) {
512+
m_obj->UpdateIPO(m_localframe, m_ipo_flags & ACT_IPOFLAG_CHILD);
513+
m_requestIpo = false;
514+
}
505515

506516
// If the action is done we can remove its scene graph IPO controller.
507517
if (m_done) {

source/gameengine/Ketsji/BL_Action.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class BL_Action
7272
* to the object.
7373
*/
7474
bool m_appliedToObject;
75+
76+
/// Set to true when the action was updated and applied. Back to false in the IPO update (UpdateIPO).
77+
bool m_requestIpo;
7578
bool m_calc_localtime;
7679

7780
// The last update time to avoid double animation update.

source/gameengine/Ketsji/BL_ActionManager.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,11 @@ bool BL_ActionManager::IsActionDone(short layer)
149149

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

158-
void BL_ActionManager::UpdateIPOs()
159-
{
160-
for (BL_ActionMap::iterator it = m_layers.begin(); it != m_layers.end(); ++it) {
161-
it->second->UpdateIPOs();
156+
for (const auto& pair : m_layers) {
157+
pair.second->UpdateIPOs();
162158
}
163159
}

source/gameengine/Ketsji/BL_ActionManager.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,6 @@ class BL_ActionManager
123123
*/
124124
void Update(float curtime, bool applyToObject);
125125

126-
/**
127-
* Update object IPOs (note: not thread-safe!)
128-
*/
129-
void UpdateIPOs();
130-
131126
#ifdef WITH_CXX_GUARDEDALLOC
132127
MEM_CXX_CLASS_ALLOC_FUNCS("GE:BL_ActionManager")
133128
#endif

source/gameengine/Ketsji/KX_GameObject.cpp

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "SG_Controller.h"
5454
#include "PHY_IGraphicController.h"
5555
#include "SG_Node.h"
56+
#include "SG_Familly.h"
5657
#include "KX_ClientObjectInfo.h"
5758
#include "RAS_BucketManager.h"
5859
#include "KX_RayCast.h"
@@ -476,11 +477,6 @@ void KX_GameObject::UpdateActionManager(float curtime, bool applyToObject)
476477
GetActionManager()->Update(curtime, applyToObject);
477478
}
478479

479-
void KX_GameObject::UpdateActionIPOs()
480-
{
481-
GetActionManager()->UpdateIPOs();
482-
}
483-
484480
float KX_GameObject::GetActionFrame(short layer)
485481
{
486482
return GetActionManager()->GetActionFrame(layer);
@@ -887,9 +883,8 @@ void KX_GameObject::UpdateIPO(float curframetime,
887883
bool recurse)
888884
{
889885
// just the 'normal' update procedure.
890-
GetSGNode()->SetSimulatedTime(curframetime,recurse);
891-
GetSGNode()->UpdateWorldData(curframetime);
892-
UpdateTransform();
886+
GetSGNode()->SetSimulatedTimeThread(curframetime,recurse);
887+
GetSGNode()->UpdateWorldDataThread(curframetime);
893888
}
894889

895890
bool

source/gameengine/Ketsji/KX_GameObject.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,6 @@ class KX_GameObject : public SCA_IObject
326326
*/
327327
void UpdateActionManager(float curtime, bool applyObject);
328328

329-
/**
330-
* Have the action manager update IPOs
331-
* note: not thread-safe!
332-
*/
333-
void UpdateActionIPOs();
334-
335329
/*********************************
336330
* End Animation API
337331
*********************************/

source/gameengine/Ketsji/KX_KetsjiEngine.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,6 @@ void KX_KetsjiEngine::EndFrame()
309309

310310
bool KX_KetsjiEngine::NextFrame()
311311
{
312-
313312
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
314313

315314
/*

source/gameengine/Ketsji/KX_Scene.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,9 @@ KX_Scene::KX_Scene(SCA_IInputDevice *inputDevice,
212212
default:
213213
m_obstacleSimulation = nullptr;
214214
}
215-
215+
216+
m_animationPool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &m_animationPoolData);
217+
216218
#ifdef WITH_PYTHON
217219
m_attr_dict = nullptr;
218220

@@ -240,6 +242,10 @@ KX_Scene::~KX_Scene()
240242
if (m_obstacleSimulation)
241243
delete m_obstacleSimulation;
242244

245+
if (m_animationPool) {
246+
BLI_task_pool_free(m_animationPool);
247+
}
248+
243249
if (m_objectlist)
244250
m_objectlist->Release();
245251

@@ -1547,7 +1553,8 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t
15471553
KX_GameObject *gameobj, *child, *parent;
15481554
CListValue *children;
15491555
bool needs_update;
1550-
double curtime = *(double*)BLI_task_pool_userdata(pool);
1556+
KX_Scene::AnimationPoolData *data = (KX_Scene::AnimationPoolData *)BLI_task_pool_userdata(pool);
1557+
double curtime = data->curtime;
15511558

15521559
gameobj = (KX_GameObject*)taskdata;
15531560

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

16121619
void KX_Scene::UpdateAnimations(double curtime)
16131620
{
1614-
TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime);
1621+
m_animationPoolData.curtime = curtime;
16151622

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

1620-
BLI_task_pool_work_and_wait(pool);
1621-
BLI_task_pool_free(pool);
1622-
1623-
for (CListValue::iterator<KX_GameObject> it = m_animatedlist->GetBegin(), end = m_animatedlist->GetEnd(); it != end; ++it) {
1624-
(*it)->UpdateActionIPOs();
1625-
}
1627+
BLI_task_pool_work_and_wait(m_animationPool);
16261628
}
16271629

16281630
void KX_Scene::LogicUpdateFrame(double curtime, bool frame)

source/gameengine/Ketsji/KX_Scene.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class btCollisionShape;
8787
class KX_BlenderSceneConverter;
8888
struct KX_ClientObjectInfo;
8989
class KX_ObstacleSimulation;
90+
struct TaskPool;
9091

9192
#ifdef WITH_CXX_GUARDEDALLOC
9293
#include "MEM_guardedalloc.h"
@@ -109,6 +110,11 @@ class KX_Scene : public CValue, public SCA_IScene
109110
MAX_DRAW_CALLBACK
110111
};
111112

113+
struct AnimationPoolData
114+
{
115+
double curtime;
116+
};
117+
112118
private:
113119
Py_Header
114120

@@ -298,6 +304,9 @@ class KX_Scene : public CValue, public SCA_IScene
298304

299305
KX_ObstacleSimulation* m_obstacleSimulation;
300306

307+
AnimationPoolData m_animationPoolData;
308+
TaskPool *m_animationPool;
309+
301310
/**
302311
* LOD Hysteresis settings
303312
*/

source/gameengine/Launcher/LA_Launcher.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ void LA_Launcher::InitEngine()
227227

228228
// Create the ketsjiengine.
229229
m_ketsjiEngine = new KX_KetsjiEngine(m_kxsystem);
230-
230+
KX_SetActiveEngine(m_ketsjiEngine);
231+
231232
// Set the devices.
232233
m_ketsjiEngine->SetInputDevice(m_inputDevice);
233234
m_ketsjiEngine->SetCanvas(m_canvas);
@@ -270,7 +271,6 @@ void LA_Launcher::InitEngine()
270271
m_networkMessageManager);
271272

272273
KX_SetActiveScene(m_kxStartScene);
273-
KX_SetActiveEngine(m_ketsjiEngine);
274274

275275
#ifdef WITH_PYTHON
276276
// Some python things.

source/gameengine/SceneGraph/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
set(INC
2727
.
28+
../Common
2829
../../blender/blenlib
2930
)
3031

@@ -35,11 +36,13 @@ set(INC_SYS
3536
set(SRC
3637
SG_BBox.cpp
3738
SG_Controller.cpp
39+
SG_Familly.cpp
3840
SG_Node.cpp
3941

4042
SG_BBox.h
4143
SG_Controller.h
4244
SG_DList.h
45+
SG_Familly.h
4346
SG_Node.h
4447
SG_ParentRelation.h
4548
SG_QList.h
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* ***** BEGIN GPL LICENSE BLOCK *****
3+
*
4+
* This program is free software; you can redistribute it and/or
5+
* modify it under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation; either version 2
7+
* of the License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software Foundation,
16+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*
18+
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19+
* All rights reserved.
20+
*
21+
* The Original Code is: all of this file.
22+
*
23+
* Contributor(s): none yet.
24+
*
25+
* ***** END GPL LICENSE BLOCK *****
26+
*/
27+
28+
/** \file gameengine/SceneGraph/SG_Familly.cpp
29+
* \ingroup bgesg
30+
*/
31+
32+
#include "SG_Familly.h"
33+
34+
CM_ThreadSpinLock& SG_Familly::GetMutex()
35+
{
36+
return m_mutex;
37+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Implementationclass to derive controllers from
3+
*
4+
*
5+
* ***** BEGIN GPL LICENSE BLOCK *****
6+
*
7+
* This program is free software; you can redistribute it and/or
8+
* modify it under the terms of the GNU General Public License
9+
* as published by the Free Software Foundation; either version 2
10+
* of the License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20+
*
21+
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22+
* All rights reserved.
23+
*
24+
* The Original Code is: all of this file.
25+
*
26+
* Contributor(s): none yet.
27+
*
28+
* ***** END GPL LICENSE BLOCK *****
29+
*/
30+
31+
/** \file SG_Familly.h
32+
* \ingroup bgesg
33+
*/
34+
35+
#ifndef __SG_FAMILLY_H__
36+
#define __SG_FAMILLY_H__
37+
38+
#include "CM_Thread.h"
39+
40+
class SG_Familly
41+
{
42+
private:
43+
CM_ThreadSpinLock m_mutex;
44+
45+
public:
46+
SG_Familly() = default;
47+
~SG_Familly() = default;
48+
49+
CM_ThreadSpinLock& GetMutex();
50+
51+
};
52+
53+
#endif /* __SG_FAMILLY_H__ */

0 commit comments

Comments
 (0)