This chapter will discuss read/write access to PhysX objects which are in a scene, specifically the time frame when access is allowed and how/when the changes will take effect. For objects in different scenes or outside a scene, the restrictions are given in the multithreading guidelines in The PhysX API.
It is important to distinguish two time slots for data access:
In the first time slot, the simulation is not running and there are no restrictions for reading or writing object properties. Changes to the position of an object, for example, are applied instantaneously and the next scene query or simulation step will take the new state into account.
In the second time slot the simulation is running and in the process, reading and changing the state of objects. Concurrent access from the user might corrupt the state of the objects or lead to data races or inconsistent views in the simulation code. Hence the simulation code's view of the objects is protected from API writes, and any attributes the simulation updates are buffered to allow API reads. The consequences will be discussed in detail in the next section.
Note that simulate() and fetchResults() are write calls on the scene, and as such it is illegal to access any object in the scene while these functions are running.
While a simulation is running, PhysX supports read and write access to objects in the scene (with some exceptions, see further below). This includes adding/removing them to/from a scene.
From the user perspective, API changes are reflected immediately. For example, if the velocity of a rigid body is set and then queried, the new velocity will be returned. Similarly, if an object is created while the simulation is running, it can be accessed/modified as any other object. However, these changes are buffered so that the simulation code sees the object state as it was when PxScene::simulate() was called. For instance, changes to the filter data of an object while the simulation is running are ignored for collision pair generation of the running step, and will only affect for the next simulation step.
When PxScene::fetchResults() is called, any buffered changes are flushed: changes made by the simulation are reflected in API view of the objects, and API changes are made visible to the simulation code for the next step. User changes take precedence: for example, a user change to the position of an object while the simulation is running will overwrite the position which resulted from the simulation.
The delayed application of updates does not affect scene queries, which always take into account the latest changes.
Deleting objects or removing them from the scene while the simulation is in process will affect the simulation events sent out at PxScene::fetchResults(). The behavior is as follows:
Not all PhysX objects have full buffering support. Operations which can not run while the simulation is in process are mentioned in the API documentation and the SDK aborts such operations and reports an error. The most important exceptions are as follows:
The buffers to store the object changes while the simulation is running are created on demand. If memory usage concerns outweigh the advantage of reading/writing objects in parallel with simulation, do not write to objects while the simulation is running.
Each PxScene object provides a multiple reader, single writer lock that can be used to control access to the scene by multiple threads. This is useful for situations where the PhysX scene is shared between more than one system, for example APEX and a game engine's physics code. The scene lock provides a way for these systems to coordinate with each other.
The lock is always available and can be made mandatory by setting the PxSceneFlag::eREQUIRE_RW_LOCK flag at scene creation time. If this flag is set a warning will be issued for any API calls made without first acquiring the appropriate lock.
There are four methods for for acquiring / releasing the lock:
void PxScene::lockRead(const char* file=NULL, PxU32 line=0); void PxScene::unlockRead(); void PxScene::lockWrite(const char* file=NULL, PxU32 line=0); void PxScene::unlockWrite();
Additionally there is an RAII helper class to manage these locks, see PxSceneLock.h.
There are precise rules regarding the usage of the scene lock:
Note: PxScene::release() automatically attempts to acquire the write lock, it is not necessary to acquire it manally before calling release().