diff options
author | Mitchell Stokes <mogurijin@gmail.com> | 2014-04-07 03:30:59 +0400 |
---|---|---|
committer | Mitchell Stokes <mogurijin@gmail.com> | 2014-04-07 03:30:59 +0400 |
commit | fe05f97841c0ee3e2a6e15f2252ad160fefc3509 (patch) | |
tree | 2a672e5d82448f43471ddb529a95fa547d5c311e /source/gameengine/Ketsji/KX_Scene.cpp | |
parent | be8b4b8b0c4d4fdeed6ebf88d8a3bd480e4c48ce (diff) |
BGE: Multi-threading animation updates and skinning.
This required BL_ArmatureObject to have tighter control over armatures and poses.
Also, (Blender) armature objects are now copied instead of shared between
BL_ArmatureObjects to avoid race conditions. Also, due to the armature copy,
shape key drivers need a bit of extra fiddling to get the correct armature copy.
Initially OpenMP was used for threading, but then BLI_task was used due to being
less compiler dependent.
This commit also places time spent on skinning updates in the Animation
profiler category (was previously under the Rasterizer category).
Diffstat (limited to 'source/gameengine/Ketsji/KX_Scene.cpp')
-rw-r--r-- | source/gameengine/Ketsji/KX_Scene.cpp | 92 |
1 files changed, 58 insertions, 34 deletions
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index a9ac13c755f..fbd9eeba8ed 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -102,6 +102,8 @@ #include <stdio.h> +#include "BLI_task.h" + static void *KX_SceneReplicationFunc(SG_IObject* node,void* gameobj,void* scene) { KX_GameObject* replica = ((KX_Scene*)scene)->AddNodeReplicaObject(node,(KX_GameObject*)gameobj); @@ -1196,7 +1198,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; - modifierDeformer->LoadShapeDrivers(blendobj->parent); + modifierDeformer->LoadShapeDrivers(parentobj); } else { @@ -1224,7 +1226,7 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u static_cast<BL_ArmatureObject*>( parentobj ) ); releaseParent= false; - shapeDeformer->LoadShapeDrivers(blendobj->parent); + shapeDeformer->LoadShapeDrivers(parentobj); } else { @@ -1596,52 +1598,74 @@ void KX_Scene::AddAnimatedObject(CValue* gameobj) m_animatedlist->Add(gameobj); } -void KX_Scene::UpdateAnimations(double curtime) +static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(threadid)) { - KX_GameObject *gameobj; + KX_GameObject *gameobj, *child; + CListValue *children; bool needs_update; + double curtime = *(double*)BLI_task_pool_userdata(pool); - for (int i=0; i<m_animatedlist->GetCount(); ++i) { - gameobj = (KX_GameObject*)m_animatedlist->GetValue(i); - - // Non-armature updates are fast enough, so just update them - needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE; + gameobj = (KX_GameObject*)taskdata; - if (!needs_update) { - // If we got here, we're looking to update an armature, so check its children meshes - // to see if we need to bother with a more expensive pose update - CListValue *children = gameobj->GetChildren(); - KX_GameObject *child; + // Non-armature updates are fast enough, so just update them + needs_update = gameobj->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE; - bool has_mesh = false, has_non_mesh = false; + if (!needs_update) { + // If we got here, we're looking to update an armature, so check its children meshes + // to see if we need to bother with a more expensive pose update + children = gameobj->GetChildren(); - // Check for meshes that haven't been culled - for (int j=0; j<children->GetCount(); ++j) { - child = (KX_GameObject*)children->GetValue(j); + bool has_mesh = false, has_non_mesh = false; - if (!child->GetCulled()) { - needs_update = true; - break; - } + // Check for meshes that haven't been culled + for (int j=0; j<children->GetCount(); ++j) { + child = (KX_GameObject*)children->GetValue(j); - if (child->GetMeshCount() == 0) - has_non_mesh = true; - else - has_mesh = true; + if (!child->GetCulled()) { + needs_update = true; + break; } - // If we didn't find a non-culled mesh, check to see - // if we even have any meshes, and update if this - // armature has only non-mesh children. - if (!needs_update && !has_mesh && has_non_mesh) - needs_update = true; + if (child->GetMeshCount() == 0) + has_non_mesh = true; + else + has_mesh = true; + } + + // If we didn't find a non-culled mesh, check to see + // if we even have any meshes, and update if this + // armature has only non-mesh children. + if (!needs_update && !has_mesh && has_non_mesh) + needs_update = true; - children->Release(); + children->Release(); + } + + if (needs_update) { + gameobj->UpdateActionManager(curtime); + children = gameobj->GetChildren(); + + for (int j=0; j<children->GetCount(); ++j) { + child = (KX_GameObject*)children->GetValue(j); + + if (child->GetDeformer()) + child->GetDeformer()->Update(); } - if (needs_update) - gameobj->UpdateActionManager(curtime); + children->Release(); + } +} + +void KX_Scene::UpdateAnimations(double curtime) +{ + TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime); + + for (int i=0; i<m_animatedlist->GetCount(); ++i) { + BLI_task_pool_push(pool, update_anim_thread_func, m_animatedlist->GetValue(i), false, TASK_PRIORITY_LOW); } + + BLI_task_pool_work_and_wait(pool); + BLI_task_pool_free(pool); } void KX_Scene::LogicUpdateFrame(double curtime, bool frame) |