Log:
ephysics: use multiple threads
Use a mainloop thread and one thread per world dedicated to simulation.
It's using ecore threads, out of the pool.
For now there are still some locks when trying to change physics
elements properties while a simulation is going on, but soon it will
have a queue of properties to be applied after a simulation step, so
it won't lock.
Author: bdilly
Date: 2012-10-04 15:38:06 -0700 (Thu, 04 Oct 2012)
New Revision: 77455
Trac: http://trac.enlightenment.org/e/changeset/77455
Modified:
trunk/ephysics/src/lib/EPhysics.h trunk/ephysics/src/lib/ephysics_body.cpp trunk/ephysics/src/lib/ephysics_constraints.cpp trunk/ephysics/src/lib/ephysics_private.h trunk/ephysics/src/lib/ephysics_world.cpp
Modified: trunk/ephysics/src/lib/EPhysics.h
===================================================================
--- trunk/ephysics/src/lib/EPhysics.h 2012-10-04 22:38:00 UTC (rev 77454)
+++ trunk/ephysics/src/lib/EPhysics.h 2012-10-04 22:38:06 UTC (rev 77455)
@@ -602,7 +602,7 @@
*
* @ingroup EPhysics_World
*/
-EAPI Eina_Bool ephysics_world_serialize(const EPhysics_World *world, const char *path);
+EAPI Eina_Bool ephysics_world_serialize(EPhysics_World *world, const char *path);
/**
* @brief
Modified: trunk/ephysics/src/lib/ephysics_body.cpp
===================================================================
--- trunk/ephysics/src/lib/ephysics_body.cpp 2012-10-04 22:38:00 UTC (rev 77454)
+++ trunk/ephysics/src/lib/ephysics_body.cpp 2012-10-04 22:38:06 UTC (rev 77455)
@@ -141,15 +141,18 @@
return EINA_FALSE;
}
+ ephysics_world_lock_take(body->world);
group_str = eina_stringshare_add(group);
if (eina_list_data_find(body->collision_groups, group_str))
{
INF("Body already added to group: %s", group);
eina_stringshare_del(group_str);
+ ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
body->collision_groups = eina_list_append(body->collision_groups, group_str);
+ ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
@@ -164,17 +167,20 @@
return EINA_FALSE;
}
+ ephysics_world_lock_take(body->world);
group_str = eina_stringshare_add(group);
if (!eina_list_data_find(body->collision_groups, group_str))
{
INF("Body isn't part of group: %s", group);
eina_stringshare_del(group_str);
+ ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
body->collision_groups = eina_list_remove(body->collision_groups, group_str);
eina_stringshare_del(group_str);
eina_stringshare_del(group_str);
+ ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
@@ -342,6 +348,24 @@
}
static void
+_ephysics_body_mass_set(EPhysics_Body *body, double mass)
+{
+ btVector3 inertia(0, 0, 0);
+
+ if (body->soft_body)
+ body->soft_body->setTotalMass(mass);
+ else
+ {
+ body->collision_shape->calculateLocalInertia(mass, inertia);
+ body->rigid_body->setMassProps(mass, inertia);
+ body->rigid_body->updateInertiaTensor();
+ }
+
+ body->mass = mass;
+ DBG("Body %p mass changed to %lf.", body, mass);
+}
+
+static void
_ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h)
{
double rate, sx, sy;
@@ -360,7 +384,7 @@
body->collision_shape->setLocalScaling(btVector3(sx, sy, 1));
if(!body->rigid_body->isStaticObject())
- ephysics_body_mass_set(body, ephysics_body_mass_get(body));
+ _ephysics_body_mass_set(body, ephysics_body_mass_get(body));
}
body->w = w;
@@ -429,7 +453,7 @@
body->rigid_body->proceedToTransform(trans);
if (!body->rigid_body->isStaticObject())
- ephysics_body_mass_set(body, ephysics_body_mass_get(body));
+ _ephysics_body_mass_set(body, ephysics_body_mass_get(body));
}
body->rigid_body->getMotionState()->setWorldTransform(trans);
@@ -480,7 +504,9 @@
return;
DBG("Resizing body %p to w=%i, h=%i", body, w, h);
+ ephysics_world_lock_take(body->world);
_ephysics_body_resize(body, w, h);
+ ephysics_world_lock_release(body->world);
}
static void
@@ -708,11 +734,20 @@
return body->soft_body;
}
+static void
+_ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
+{
+ btSoftBody *soft_body = body->soft_body;
+ soft_body->m_cfg.kAHR = (hardness / 100) * 0.6;
+ soft_body->m_materials[0]->m_kVST = (hardness / 100);
+ soft_body->m_materials[0]->m_kLST = (hardness / 100);
+ soft_body->m_materials[0]->m_kAST = (hardness / 100);
+ DBG("Soft body %p hardness set to %lf.", body, hardness);
+}
+
EAPI void
ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
{
- btSoftBody *soft_body;
-
if (!body)
{
ERR("Can't set soft body's hardness, body is null.");
@@ -731,12 +766,9 @@
return;
}
- soft_body = body->soft_body;
- soft_body->m_cfg.kAHR = (hardness / 100) * 0.6;
- soft_body->m_materials[0]->m_kVST = (hardness / 100);
- soft_body->m_materials[0]->m_kLST = (hardness / 100);
- soft_body->m_materials[0]->m_kAST = (hardness / 100);
- DBG("Soft body hardness set.");
+ ephysics_world_lock_take(body->world);
+ _ephysics_body_soft_body_hardness_set(body, hardness);
+ ephysics_world_lock_release(body->world);
}
EAPI double
@@ -775,7 +807,7 @@
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::SDF_RS;
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::VF_SS;
- ephysics_body_soft_body_hardness_set(body, 100);
+ _ephysics_body_soft_body_hardness_set(body, 100);
body->rigid_body->setCollisionFlags(
btCollisionObject::CF_NO_CONTACT_RESPONSE);
@@ -799,6 +831,7 @@
return NULL;
}
+ ephysics_world_lock_take(world);
shape = new btCylinderShapeZ(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
@@ -836,6 +869,7 @@
body->points_deform[3][1] = 3;
body->points_deform[3][2] = 76;
+ ephysics_world_lock_release(world);
return body;
no_body:
@@ -843,6 +877,7 @@
no_soft_body:
delete shape;
no_collision_shape:
+ ephysics_world_lock_release(world);
return NULL;
}
@@ -850,6 +885,7 @@
ephysics_body_circle_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
+ EPhysics_Body *body;
if (!world)
{
@@ -864,7 +900,10 @@
return NULL;
}
- return _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
+ ephysics_world_lock_take(world);
+ body = _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
+ ephysics_world_lock_release(world);
+ return body;
}
EAPI EPhysics_Body *
@@ -881,6 +920,7 @@
return NULL;
}
+ ephysics_world_lock_take(world);
shape = new btBoxShape(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
@@ -918,6 +958,7 @@
body->points_deform[3][1] = 62;
body->points_deform[3][2] = 8;
+ ephysics_world_lock_release(world);
return body;
no_body:
@@ -925,6 +966,7 @@
no_soft_body:
delete shape;
no_collision_shape:
+ ephysics_world_lock_release(world);
return NULL;
}
@@ -932,6 +974,7 @@
ephysics_body_box_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
+ EPhysics_Body *body;
if (!world)
{
@@ -941,7 +984,10 @@
collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
- return _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
+ ephysics_world_lock_take(world);
+ body = _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
+ ephysics_world_lock_release(world);
+ return body;
}
EAPI EPhysics_Body *
@@ -952,6 +998,7 @@
btAlignedObjectArray<btVector3> vertexes, planes;
const Eina_Inlist *points;
EPhysics_Point *point;
+ EPhysics_Body *body;
int array_size, i;
btShapeHull *hull;
btVector3 point3d;
@@ -1052,9 +1099,12 @@
return NULL;
}
- return _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
+ ephysics_world_lock_take(world);
+ body = _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
"generic", (cm_x - min_x) / range_x,
1 - (cm_y - min_y) / range_y);
+ ephysics_world_lock_release(world);
+ return body;
}
void
@@ -1111,37 +1161,49 @@
EAPI EPhysics_Body *
ephysics_body_top_boundary_add(EPhysics_World *world)
{
+ EPhysics_Body *body;
Evas_Coord x, y, w;
+
ephysics_world_render_geometry_get(world, &x, &y, &w, NULL);
- return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_TOP,
- 0, y - 10, x + w, 10);
+ body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_TOP,
+ 0, y - 10, x + w, 10);
+ return body;
}
EAPI EPhysics_Body *
ephysics_body_bottom_boundary_add(EPhysics_World *world)
{
Evas_Coord x, y, w, h;
+ EPhysics_Body *body;
+
ephysics_world_render_geometry_get(world, &x, &y, &w, &h);
- return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM,
+ body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM,
x, y + h, w, 10);
+ return body;
}
EAPI EPhysics_Body *
ephysics_body_left_boundary_add(EPhysics_World *world)
{
+ EPhysics_Body *body;
Evas_Coord x, y, h;
+
ephysics_world_render_geometry_get(world, &x, &y, NULL, &h);
- return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_LEFT,
+ body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_LEFT,
x - 10, 0, 10, y + h);
+ return body;
}
EAPI EPhysics_Body *
ephysics_body_right_boundary_add(EPhysics_World *world)
{
Evas_Coord x, y, w, h;
+ EPhysics_Body *body;
+
ephysics_world_render_geometry_get(world, &x, &y, &w, &h);
- return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_RIGHT,
+ body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_RIGHT,
x + w, 0, 10, y + h);
+ return body;
}
void
@@ -1163,8 +1225,10 @@
}
if (body->deleted) return;
+ ephysics_world_lock_take(body->world);
body->deleted = EINA_TRUE;
ephysics_world_body_del(body->world, body);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1200,11 +1264,13 @@
if (!use_obj_pos)
return;
- evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
- _ephysics_body_evas_obj_resize_cb, body);
evas_object_geometry_get(body->evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
+ ephysics_world_lock_take(body->world);
_ephysics_body_geometry_set(body, obj_x, obj_y, obj_w, obj_h,
ephysics_world_rate_get(body->world));
+ ephysics_world_lock_release(body->world);
+ evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
+ _ephysics_body_evas_obj_resize_cb, body);
}
EAPI Evas_Object *
@@ -1258,8 +1324,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_geometry_set(body, x, y, w, h,
ephysics_world_rate_get(body->world));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1277,7 +1345,9 @@
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_resize(body, w, h);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1289,7 +1359,9 @@
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_move(body, x, y);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1329,18 +1401,9 @@
return;
}
- btVector3 inertia(0, 0, 0);
- if (body->soft_body)
- body->soft_body->setTotalMass(mass);
- else
- {
- body->collision_shape->calculateLocalInertia(mass, inertia);
- body->rigid_body->setMassProps(mass, inertia);
- body->rigid_body->updateInertiaTensor();
- }
- body->mass = mass;
-
- DBG("Body %p mass changed to %lf.", body, mass);
+ ephysics_world_lock_take(body->world);
+ _ephysics_body_mass_set(body, mass);
+ ephysics_world_lock_release(body->world);
}
EAPI double
@@ -1394,8 +1457,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setAngularVelocity(btVector3(0, 0, -z/RAD_TO_DEG));
DBG("Angular velocity of body %p set to %lf", body, z);
+ ephysics_world_lock_release(body->world);
}
EAPI double
@@ -1419,9 +1484,11 @@
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_sleeping_threshold_set(body, linear_threshold,
angular_threshold,
ephysics_world_rate_get(body->world));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1452,8 +1519,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setLinearVelocity(btVector3(0, 0, 0));
body->rigid_body->setAngularVelocity(btVector3(0, 0, 0));
+ ephysics_world_lock_release(body->world);
DBG("Body %p stopped", body);
}
@@ -1467,8 +1536,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setDamping(btScalar(linear_damping),
btScalar(angular_damping));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1594,7 +1665,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setRestitution(btScalar(restitution));
+ DBG("Body %p restitution set to %lf", body, restitution);
+ ephysics_world_lock_release(body->world);
}
EAPI double
@@ -1618,7 +1692,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setFriction(btScalar(friction));
+ DBG("Body %p friction set to %lf", body, friction);
+ ephysics_world_lock_release(body->world);
}
EAPI double
@@ -1658,8 +1735,10 @@
rate = ephysics_world_rate_get(body->world);
+ ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyCentralImpulse(btVector3(x / rate, - y / rate, 0));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1675,10 +1754,12 @@
rate = ephysics_world_rate_get(body->world);
+ ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyImpulse(btVector3(x / rate, - y / rate, 0),
btVector3((double) pos_x / rate,
(double) pos_y / rate, 0));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1690,7 +1771,9 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->setLinearFactor(btVector3(!!enable_x, !!enable_y, 0));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1715,8 +1798,10 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyTorqueImpulse(btVector3(0, 0, -roll));
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1728,10 +1813,12 @@
return;
}
+ ephysics_world_lock_take(body->world);
if (!enable)
body->rigid_body->setAngularFactor(btVector3(0, 0, 0));
else
body->rigid_body->setAngularFactor(btVector3(0, 0, 1));
+ ephysics_world_lock_release(body->world);
}
EAPI Eina_Bool
@@ -1777,6 +1864,7 @@
return;
}
+ ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->getMotionState()->getWorldTransform(trans);
quat.setEuler(0, 0, -rotation / RAD_TO_DEG);
@@ -1789,6 +1877,7 @@
body->rigid_body->getMotionState()->setWorldTransform(trans);
DBG("Body %p rotation set to %lf", body, rotation);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1826,10 +1915,12 @@
return;
}
+ ephysics_world_lock_take(body->world);
rate = ephysics_world_rate_get(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyCentralForce(btVector3(x / rate, - y / rate, 0));
_ephysics_body_forces_update(body);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1844,11 +1935,13 @@
}
rate = ephysics_world_rate_get(body->world);
+ ephysics_world_lock_take(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyForce(btVector3(x / rate, - y / rate, 0),
btVector3((double) pos_x / rate,
(double) pos_y / rate, 0));
_ephysics_body_forces_update(body);
+ ephysics_world_lock_release(body->world);
}
EAPI void
@@ -1860,9 +1953,11 @@
return;
}
+ ephysics_world_lock_take(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyTorque(btVector3(0, 0, -torque));
_ephysics_body_forces_update(body);
+ ephysics_world_lock_release(body->world);
}
EAPI void
Modified: trunk/ephysics/src/lib/ephysics_constraints.cpp
===================================================================
--- trunk/ephysics/src/lib/ephysics_constraints.cpp 2012-10-04 22:38:00 UTC (rev 77454)
+++ trunk/ephysics/src/lib/ephysics_constraints.cpp 2012-10-04 22:38:06 UTC (rev 77455)
@@ -56,7 +56,6 @@
}
constraint->type = EPHYSICS_CONSTRAINT_P2P;
- constraint->world = ephysics_body_world_get(constraint->p2p.body1);
ephysics_world_constraint_add(constraint->world, constraint,
constraint->bt_constraint);
@@ -127,6 +126,7 @@
return NULL;
}
+ ephysics_world_lock_take(ephysics_body_world_get(body));
trans.setIdentity();
constraint->bt_constraint = new
btGeneric6DofConstraint(*ephysics_body_rigid_body_get(body), trans,
@@ -145,6 +145,7 @@
constraint->bt_constraint);
INF("Constraint added.");
+ ephysics_world_lock_release(ephysics_body_world_get(body));
return constraint;
}
@@ -163,9 +164,11 @@
return;
}
+ ephysics_world_lock_take(constraint->world);
_ephysics_constraint_slider_linear_limit_set(
constraint, left_x, under_y, right_x, above_y,
ephysics_world_rate_get(constraint->world));
+ ephysics_world_lock_release(constraint->world);
}
EAPI void
@@ -219,11 +222,13 @@
return;
}
+ ephysics_world_lock_take(constraint->world);
slider_constraint = (btGeneric6DofConstraint *)constraint->bt_constraint;
slider_constraint->setAngularLowerLimit(btVector3(0, 0,
-counter_clock_z/RAD_TO_DEG));
slider_constraint->setAngularUpperLimit(btVector3(0, 0,
clock_wise_z/RAD_TO_DEG));
+ ephysics_world_lock_release(constraint->world);
}
EAPI void
@@ -284,6 +289,7 @@
return NULL;
}
+ constraint->world = ephysics_body_world_get(body1);
constraint->p2p.body1 = body1;
constraint->p2p.body2 = body2;
constraint->p2p.anchor_b1_x = anchor_b1_x;
@@ -291,11 +297,17 @@
constraint->p2p.anchor_b2_x = anchor_b2_x;
constraint->p2p.anchor_b2_y = anchor_b2_y;
+ ephysics_world_lock_take(constraint->world);
if (!_ephysics_constraint_p2p_set(
constraint, ephysics_world_rate_get(ephysics_body_world_get(
constraint->p2p.body1))))
- return NULL;
+ {
+ ephysics_world_lock_release(constraint->world);
+ free(constraint);
+ return NULL;
+ }
+ ephysics_world_lock_release(constraint->world);
INF("Constraint added.");
return constraint;
}
@@ -309,12 +321,14 @@
return;
}
+ ephysics_world_lock_take(constraint->world);
ephysics_world_constraint_del(constraint->world, constraint,
constraint->bt_constraint);
delete constraint->bt_constraint;
free(constraint);
INF("Constraint deleted.");
+ ephysics_world_lock_release(constraint->world);
}
Modified: trunk/ephysics/src/lib/ephysics_private.h
===================================================================
--- trunk/ephysics/src/lib/ephysics_private.h 2012-10-04 22:38:00 UTC (rev 77454)
+++ trunk/ephysics/src/lib/ephysics_private.h 2012-10-04 22:38:06 UTC (rev 77455)
@@ -121,6 +121,8 @@
void ephysics_body_active_set(EPhysics_Body *body, Eina_Bool active);
void ephysics_body_recalc(EPhysics_Body *body, double rate);
void ephysics_body_forces_apply(EPhysics_Body *body);
+void ephysics_world_lock_take(EPhysics_World *world);
+void ephysics_world_lock_release(EPhysics_World *world);
/* Camera */
EPhysics_Camera *ephysics_camera_add(EPhysics_World *world);
Modified: trunk/ephysics/src/lib/ephysics_world.cpp
===================================================================
--- trunk/ephysics/src/lib/ephysics_world.cpp 2012-10-04 22:38:00 UTC (rev 77454)
+++ trunk/ephysics/src/lib/ephysics_world.cpp 2012-10-04 22:38:06 UTC (rev 77455)
@@ -12,6 +12,16 @@
#define DEFAULT_GRAVITY btVector3(0, -9.8, 0)
+typedef struct _Simulation_Msg Simulation_Msg;
+
+struct _Simulation_Msg {
+ EPhysics_Body *body_0;
+ EPhysics_Body *body_1;
+ btVector3 pos_a;
+ btVector3 pos_b;
+ Eina_Bool tick:1;
+};
+
typedef struct _EPhysics_World_Callback EPhysics_World_Callback;
struct _EPhysics_World_Callback {
@@ -41,14 +51,18 @@
Eina_List *to_delete;
Eina_List *cb_to_delete;
Eina_List *constraints;
+ Ecore_Thread *simulation_th;
+ Ecore_Thread *cur_th;
int max_sub_steps;
- int walking;
int cb_walking;
int soft_body_ref;
+ int pending_ticks;
double last_update;
double rate;
double fixed_time_step;
double max_sleeping_time;
+ Eina_Lock mutex;
+ Eina_Condition condition;
Eina_Bool running:1;
Eina_Bool active:1;
Eina_Bool deleted:1;
@@ -57,6 +71,7 @@
Eina_Bool outside_bottom:1;
Eina_Bool outside_left:1;
Eina_Bool outside_right:1;
+ Eina_Bool pending_simulation:1;
};
static int _ephysics_world_init_count = 0;
@@ -101,6 +116,14 @@
}
static void
+_ephysics_world_th_cancel(EPhysics_World *world)
+{
+ _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
+ if (!ecore_thread_cancel(world->simulation_th))
+ eina_condition_signal(&world->condition);
+}
+
+static void
_ephysics_world_event_callback_call(EPhysics_World *world, EPhysics_Callback_World_Type type, void *event_info)
{
EPhysics_World_Callback *cb;
@@ -144,7 +167,7 @@
}
static void
-_ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep __UNUSED__)
+_ephysics_world_tick(btDynamicsWorld *dynamics_world)
{
Eina_Bool world_active, camera_moved, tx, ty;
btCollisionObjectArray objects;
@@ -195,16 +218,44 @@
world, EPHYSICS_CALLBACK_WORLD_CAMERA_MOVED, world->camera);
}
-
- if (world->active == world_active) return;
+ if (world->active == world_active) goto body_del;
world->active = world_active;
- if (world_active) return;
+ if (world_active) goto body_del;
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_STOPPED,
NULL);
+
+body_del:
+ world->pending_ticks--;
+ if (!world->pending_ticks)
+ {
+ void *bd;
+ EINA_LIST_FREE(world->to_delete, bd)
+ ephysics_world_body_del(world, (EPhysics_Body*)bd);
+ }
+
+ if ((world->pending_simulation) && (!world->pending_ticks))
+ {
+ world->pending_simulation = EINA_FALSE;
+ eina_condition_signal(&world->condition);
+ }
}
static void
+_ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep __UNUSED__)
+{
+ EPhysics_World *world;
+ Simulation_Msg *msg;
+
+ msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
+ msg->tick = EINA_TRUE;
+
+ world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
+ world->pending_ticks++;
+ ecore_thread_feedback(world->cur_th, msg);
+}
+
+static void
_ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
{
btSoftBody *soft_body;
@@ -227,7 +278,7 @@
{
EPhysics_Body *bd;
- if (world->walking)
+ if (world->pending_ticks)
{
world->to_delete = eina_list_append(world->to_delete, body);
return EINA_FALSE;
@@ -255,8 +306,6 @@
EPhysics_Body *body;
void *constraint;
- _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
-
while (world->callbacks)
{
cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
@@ -286,6 +335,9 @@
delete world->soft_solver;
delete world->world_info;
+ eina_condition_free(&world->condition);
+ eina_lock_free(&world->mutex);
+
free(world);
INF("World %p deleted.", world);
}
@@ -294,46 +346,24 @@
_simulate_worlds(void *data __UNUSED__)
{
EPhysics_World *world;
- void *wrld, *bd;
+ void *wrld;
ephysics_init();
_worlds_walking++;
EINA_INLIST_FOREACH(_worlds, world)
{
- double time_now, delta;
- EPhysics_Body *body;
-
if (!world->running)
continue;
- world->walking++;
-
- EINA_INLIST_FOREACH(world->bodies, body)
- ephysics_body_forces_apply(body);
-
- time_now = ecore_time_get();
- delta = time_now - world->last_update;
- world->last_update = time_now;
-
- gDeactivationTime = world->max_sleeping_time;
-
- if (world->soft_body_ref)
+ if (world->pending_ticks)
{
- world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
- world->fixed_time_step);
- world->world_info->m_sparsesdf.GarbageCollect();
+ world->pending_simulation = EINA_TRUE;
+ continue;
}
- else
- ((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
- delta, world->max_sub_steps, world->fixed_time_step);
- world->walking--;
+ world->pending_simulation = EINA_FALSE;
- if (!world->walking)
- {
- EINA_LIST_FREE(world->to_delete, bd)
- ephysics_world_body_del(world, (EPhysics_Body*)bd);
- }
+ eina_condition_signal(&world->condition);
}
_worlds_walking--;
@@ -344,7 +374,7 @@
}
EINA_LIST_FREE(_worlds_to_delete, wrld)
- _ephysics_world_free((EPhysics_World *)wrld);
+ _ephysics_world_th_cancel((EPhysics_World *)wrld);
ephysics_shutdown();
@@ -356,6 +386,8 @@
{
btRigidBody *rigid_body_0, *rigid_body_1;
EPhysics_Body *body_0, *body_1;
+ EPhysics_World *world;
+ Simulation_Msg *msg;
rigid_body_0 = (btRigidBody *) b0;
rigid_body_1 = (btRigidBody *) b1;
@@ -363,9 +395,15 @@
body_0 = (EPhysics_Body *) rigid_body_0->getUserPointer();
body_1 = (EPhysics_Body *) rigid_body_1->getUserPointer();
- ephysics_body_contact_processed(body_0, body_1, cp.getPositionWorldOnA());
- ephysics_body_contact_processed(body_1, body_0, cp.getPositionWorldOnB());
+ world = ephysics_body_world_get(body_0);
+ msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
+ msg->body_0 = body_0;
+ msg->body_1 = body_1;
+ msg->pos_a = cp.getPositionWorldOnA();
+ msg->pos_b = cp.getPositionWorldOnB();
+ ecore_thread_feedback(world->cur_th, msg);
+
return EINA_TRUE;
}
@@ -485,6 +523,85 @@
return world->boundaries[boundary];
}
+static void
+_th_simulate(void *data, Ecore_Thread *th)
+{
+ EPhysics_World *world = (EPhysics_World *) data;
+
+ while (1)
+ {
+ double time_now, delta;
+ EPhysics_Body *body;
+
+ eina_condition_wait(&world->condition);
+ if (ecore_thread_check(th))
+ {
+ INF("Thread canceled by main loop thread");
+ eina_lock_release(&world->mutex);
+ return;
+ }
+
+ world->pending_ticks++;
+ world->cur_th = th;
+
+ EINA_INLIST_FOREACH(world->bodies, body)
+ ephysics_body_forces_apply(body);
+
+ time_now = ecore_time_get();
+ delta = time_now - world->last_update;
+ world->last_update = time_now;
+
+ gDeactivationTime = world->max_sleeping_time;
+
+ if (world->soft_body_ref)
+ {
+ world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
+ world->fixed_time_step);
+ world->world_info->m_sparsesdf.GarbageCollect();
+ }
+ else
+ ((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
+ delta, world->max_sub_steps, world->fixed_time_step);
+
+ world->pending_ticks--;
+ eina_lock_release(&world->mutex);
+ }
+}
+
+static void
+_th_msg_cb(void *data, Ecore_Thread *th __UNUSED__, void *msg_data)
+{
+ EPhysics_World *world = (EPhysics_World *) data;
+ Simulation_Msg *msg = (Simulation_Msg *) msg_data;
+
+ if (msg->tick)
+ _ephysics_world_tick(world->dynamics_world);
+ else
+ {
+ ephysics_body_contact_processed(msg->body_0, msg->body_1, msg->pos_a);
+ ephysics_body_contact_processed(msg->body_1, msg->body_0, msg->pos_b);
+ }
+ free(msg);
+}
+
+static void
+_th_end_cb(void *data, Ecore_Thread *th)
+{
+ EPhysics_World *world = (EPhysics_World *) data;
+ INF("World %p simulation thread %p end", world, th);
+ world->simulation_th = NULL;
+ _ephysics_world_free(world);
+}
+
+static void
+_th_cancel_cb(void *data, Ecore_Thread *th)
+{
+ EPhysics_World *world = (EPhysics_World *) data;
+ INF("World %p simulation thread %p canceled", world, th);
+ world->simulation_th = NULL;
+ _ephysics_world_free(world);
+}
+
EAPI EPhysics_World *
ephysics_world_new(void)
{
@@ -566,6 +683,15 @@
ERR("Couldn't add world to worlds list.");
goto no_list;
}
+ world->simulation_th = ecore_thread_feedback_run(
+ _th_simulate, _th_msg_cb, _th_end_cb, _th_cancel_cb, world, EINA_TRUE);
+ if (!world->simulation_th)
+ {
+ ERR("Failed to create simulation thread.");
+ goto no_thread;
+ }
+ eina_lock_new(&world->mutex);
+ eina_condition_new(&world->condition, &world->mutex);
world->dynamics_world->getSolverInfo().m_solverMode ^=
EPHYSICS_WORLD_SOLVER_SIMD;
@@ -594,6 +720,8 @@
INF("World %p added.", world);
return world;
+no_thread:
+ _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
no_list:
delete world->world_info;
no_world_info:
@@ -616,7 +744,7 @@
}
EAPI Eina_Bool
-ephysics_world_serialize(const EPhysics_World *world, const char *path)
+ephysics_world_serialize(EPhysics_World *world, const char *path)
{
btDefaultSerializer *serializer;
FILE *file;
@@ -627,10 +755,13 @@
return EINA_FALSE;
}
+ eina_lock_take(&world->mutex);
+
file = fopen(path, "wb");
if (!file)
{
WRN("Could not serialize, could not open file: %s", path);
+ eina_lock_release(&world->mutex);
return EINA_FALSE;
}
@@ -643,6 +774,7 @@
WRN("Problems on writing to: %s.", path);
fclose(file);
delete serializer;
+ eina_lock_release(&world->mutex);
return EINA_FALSE;
}
@@ -651,9 +783,45 @@
INF("Serialization of world %p written to file: %s.", world, path);
+ eina_lock_release(&world->mutex);
return EINA_TRUE;
}
+static void
+_ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
+{
+ if ((!!running) == world->running) return;
+
+ world->running = !!running;
+
+ if (world->running)
+ {
+ world->last_update = ecore_time_get();
+ _worlds_running++;
+ INF("World unpaused.");
+ }
+ else
+ {
+ _worlds_running--;
+ INF("World paused.");
+ }
+
+ if (!_worlds_running)
+ {
+ if (_anim_simulate)
+ {
+ ecore_animator_del(_anim_simulate);
+ _anim_simulate = NULL;
+ }
+ return;
+ }
+
+ if (_anim_simulate)
+ return;
+
+ _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
+}
+
EAPI void
ephysics_world_del(EPhysics_World *world)
{
@@ -665,19 +833,23 @@
if (world->deleted) return;
+ eina_lock_take(&world->mutex);
+
world->deleted = EINA_TRUE;
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_DEL,
NULL);
- ephysics_world_running_set(world, EINA_FALSE);
+ _ephysics_world_running_set(world, EINA_FALSE);
if (_worlds_walking > 0)
{
_worlds_to_delete = eina_list_append(_worlds_to_delete, world);
INF("World %p marked to delete.", world);
+ eina_lock_release(&world->mutex);
return;
}
- _ephysics_world_free(world);
+ eina_lock_release(&world->mutex);
+ _ephysics_world_th_cancel(world);
}
EAPI void
@@ -689,36 +861,9 @@
return;
}
- if ((!!running) == world->running) return;
-
- world->running = !!running;
-
- if (world->running)
- {
- world->last_update = ecore_time_get();
- _worlds_running++;
- INF("World unpaused.");
- }
- else
- {
- _worlds_running--;
- INF("World paused.");
- }
-
- if (!_worlds_running)
- {
- if (_anim_simulate)
- {
- ecore_animator_del(_anim_simulate);
- _anim_simulate = NULL;
- }
- return;
- }
-
- if (_anim_simulate)
- return;
-
- _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
+ eina_lock_take(&world->mutex);
+ _ephysics_world_running_set(world, running);
+ eina_lock_release(&world->mutex);
}
EAPI Eina_Bool
@@ -742,7 +887,9 @@
return;
}
+ eina_lock_take(&world->mutex);
world->max_sleeping_time = sleeping_time;
+ eina_lock_release(&world->mutex);
}
EAPI double
@@ -766,8 +913,10 @@
return;
}
+ eina_lock_take(&world->mutex);
_ephysics_world_gravity_set(world, gx, gy, world->rate);
DBG("World %p gravity set to X:%lf, Y:%lf.", world, gx, gy);
+ eina_lock_release(&world->mutex);
}
EAPI void
@@ -779,7 +928,9 @@
return;
}
+ eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_numIterations = iterations;
+ eina_lock_release(&world->mutex);
}
EAPI int
@@ -804,10 +955,12 @@
return;
}
+ eina_lock_take(&world->mutex);
current_solver_mode = world->dynamics_world->getSolverInfo().m_solverMode;
if ((enable && !(current_solver_mode & solver_mode)) ||
(!enable && (current_solver_mode & solver_mode)))
world->dynamics_world->getSolverInfo().m_solverMode ^= solver_mode;
+ eina_lock_release(&world->mutex);
}
EAPI Eina_Bool
@@ -860,6 +1013,7 @@
return;
}
+ eina_lock_take(&world->mutex);
/* Force to recalculate sizes, velocities and accelerations with new rate */
ephysics_world_gravity_get(world, &gx, &gy);
_ephysics_world_gravity_set(world, gx, gy, rate);
@@ -871,6 +1025,7 @@
ephysics_constraint_recalc((EPhysics_Constraint *)constraint, rate);
world->rate = rate;
+ eina_lock_release(&world->mutex);
}
EAPI double
@@ -1050,7 +1205,9 @@
return;
}
+ eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_linearSlop = btScalar(linear_slop);
+ eina_lock_release(&world->mutex);
}
EAPI double
@@ -1202,11 +1359,13 @@
return;
}
+ eina_lock_take(&world->mutex);
world->max_sub_steps = max_sub_steps;
world->fixed_time_step = fixed_time_step;
DBG("World %p simulation set to fixed time step: %lf, max substeps:%i.",
world, fixed_time_step, max_sub_steps);
+ eina_lock_release(&world->mutex);
}
EAPI void
@@ -1222,6 +1381,18 @@
if (max_sub_steps) *max_sub_steps = world->max_sub_steps;
}
+void
+ephysics_world_lock_take(EPhysics_World *world)
+{
+ eina_lock_take(&world->mutex);
+}
+
+void
+ephysics_world_lock_release(EPhysics_World *world)
+{
+ eina_lock_release(&world->mutex);
+}
+
#ifdef __cplusplus
}
#endif
|