Articulations are aligned to 128 bytes so we can use a single pointer to either a rigid body or articulation in constraints, with the lower bits of the articulation pointer tell us which link within the articulation the constraint references.
As an example, here in PxsIslandManagerTypes.h:
/**
\brief An index describing how to access body0
\note If body0 is a dynamic (eBODY) rigid body then solverBody0 is an index into PxsIslandObjects::bodies.
\note If body0 is a kinematic (eKINEMATIC) rigid body then solverBody0 is an index into PxsIslandManager::getActiveKinematics.
\note If body0 is a static (eWORLD) then solverBody0 is PX_MAX_U32 or PX_MAX_U64, depending on the platform being 32- or 64-bit.
\note If body0 is an articulation then the articulation is found directly from Dy::getArticulation(articulation0)
*/
union
{
PxsNodeType solverBody0;
Dy::ArticulationLinkHandle articulation0;
};
We don’t make use that of that PX_SERIAL_FILE_ALIGN within the rest of the SDK so searching for it won’t show up where the restrictions originate from. However, this is a requirement that it would be risky to try and disable - it may work if you don’t use some features but for the amount of risk and effort required to switch to 16-byte aligned serial buffers, you could have just as easily allocated a 128-byte aligned buffer and not incur any risk of random failures.
Allocating 128 byte aligned pointer is fairly straightforward. Just allocate more data than you need and get an aligned pointer within the range of memory you allocated.
Releasing that buffer can be a little tricky. What I would suggest is as follows:
When allocating the memory, do something like this:
void* allocate128Aligned(size_t size)
{
size_t pointer = reinterpret_cast<size_t>(malloc(size + 256)); //allocate an extra 256 bytes for padding
size_t* ptr = reinterpret_cast<size_t*>((pointer + 128) & (~127)); //pad to the next 128 byte alignment
*(ptr - 1) = pointer; //Store the original pointer you allocated in the preceding memory address so you can look it up during release to get the originally-allocated pointer.
return ptr;
}
In release, you do the following:
void Free128(void* address)
{
size_t baseAddress = (reinterpret_cast<size_t>(address) - 1); //Retrieve the original pointer from address - 1
free(reinterpret_cast<void*>(baseAddress);
}
The above code wastes a bit of memory - you could allocate less and align using (pointer+127)&(~127) but then you could not safely ensure there was space to store the original pointer and, without that, deallocating could be tricky.