Avatar serializing: use memcpy where possible, take copy of joint data to avoid holding lock, etc

This commit is contained in:
Simon Walton 2018-08-31 15:06:33 -07:00
parent 33db1394e6
commit e1d51a6c42

View file

@ -363,13 +363,13 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags)); memcpy(destinationBuffer, &packetStateFlags, sizeof(packetStateFlags));
destinationBuffer += sizeof(packetStateFlags); destinationBuffer += sizeof(packetStateFlags);
#define AVATAR_MEMCPY(src) \
memcpy(destinationBuffer, &(src), sizeof(src)); \
destinationBuffer += sizeof(src);
if (hasAvatarGlobalPosition) { if (hasAvatarGlobalPosition) {
auto startSection = destinationBuffer; auto startSection = destinationBuffer;
auto data = reinterpret_cast<AvatarDataPacket::AvatarGlobalPosition*>(destinationBuffer); AVATAR_MEMCPY(_globalPosition);
data->globalPosition[0] = _globalPosition.x;
data->globalPosition[1] = _globalPosition.y;
data->globalPosition[2] = _globalPosition.z;
destinationBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
int numBytes = destinationBuffer - startSection; int numBytes = destinationBuffer - startSection;
@ -380,17 +380,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (hasAvatarBoundingBox) { if (hasAvatarBoundingBox) {
auto startSection = destinationBuffer; auto startSection = destinationBuffer;
auto data = reinterpret_cast<AvatarDataPacket::AvatarBoundingBox*>(destinationBuffer); AVATAR_MEMCPY(_globalBoundingBoxDimensions);
AVATAR_MEMCPY(_globalBoundingBoxOffset);
data->avatarDimensions[0] = _globalBoundingBoxDimensions.x;
data->avatarDimensions[1] = _globalBoundingBoxDimensions.y;
data->avatarDimensions[2] = _globalBoundingBoxDimensions.z;
data->boundOriginOffset[0] = _globalBoundingBoxOffset.x;
data->boundOriginOffset[1] = _globalBoundingBoxOffset.y;
data->boundOriginOffset[2] = _globalBoundingBoxOffset.z;
destinationBuffer += sizeof(AvatarDataPacket::AvatarBoundingBox);
int numBytes = destinationBuffer - startSection; int numBytes = destinationBuffer - startSection;
if (outboundDataRateOut) { if (outboundDataRateOut) {
@ -424,13 +415,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (hasLookAtPosition) { if (hasLookAtPosition) {
auto startSection = destinationBuffer; auto startSection = destinationBuffer;
auto data = reinterpret_cast<AvatarDataPacket::LookAtPosition*>(destinationBuffer); AVATAR_MEMCPY(_headData->getLookAtPosition());
auto lookAt = _headData->getLookAtPosition();
data->lookAtPosition[0] = lookAt.x;
data->lookAtPosition[1] = lookAt.y;
data->lookAtPosition[2] = lookAt.z;
destinationBuffer += sizeof(AvatarDataPacket::LookAtPosition);
int numBytes = destinationBuffer - startSection; int numBytes = destinationBuffer - startSection;
if (outboundDataRateOut) { if (outboundDataRateOut) {
outboundDataRateOut->lookAtPositionRate.increment(numBytes); outboundDataRateOut->lookAtPositionRate.increment(numBytes);
@ -531,12 +516,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (hasAvatarLocalPosition) { if (hasAvatarLocalPosition) {
auto startSection = destinationBuffer; auto startSection = destinationBuffer;
auto data = reinterpret_cast<AvatarDataPacket::AvatarLocalPosition*>(destinationBuffer); AVATAR_MEMCPY(getLocalPosition());
auto localPosition = getLocalPosition();
data->localPosition[0] = localPosition.x;
data->localPosition[1] = localPosition.y;
data->localPosition[2] = localPosition.z;
destinationBuffer += sizeof(AvatarDataPacket::AvatarLocalPosition);
int numBytes = destinationBuffer - startSection; int numBytes = destinationBuffer - startSection;
if (outboundDataRateOut) { if (outboundDataRateOut) {
@ -572,14 +552,17 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
auto startSection = destinationBuffer; auto startSection = destinationBuffer;
QReadLocker readLock(&_jointDataLock); QReadLocker readLock(&_jointDataLock);
const QVector<JointData> jointData(_jointData);
readLock.unlock(); // Unlock quickly.
// joint rotation data // joint rotation data
int numJoints = _jointData.size(); int numJoints = jointData.size();
*destinationBuffer++ = (uint8_t)numJoints; *destinationBuffer++ = (uint8_t)numJoints;
unsigned char* validityPosition = destinationBuffer; unsigned char* validityPosition = destinationBuffer;
unsigned char validity = 0; unsigned char validity = 0;
int validityBit = 0; int validityBit = 0;
int numValidityBytes = (int)std::ceil(numJoints / (float)BITS_IN_BYTE); int numValidityBytes = (numJoints + BITS_IN_BYTE - 1) / BITS_IN_BYTE;
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
int rotationSentCount = 0; int rotationSentCount = 0;
@ -595,24 +578,19 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
localSentJointDataOut.resize(numJoints); // Make sure the destination is resized before using it localSentJointDataOut.resize(numJoints); // Make sure the destination is resized before using it
} }
float minRotationDOT = !distanceAdjust ? AVATAR_MIN_ROTATION_DOT : getDistanceBasedMinRotationDOT(viewerPosition); float minRotationDOT = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinRotationDOT(viewerPosition) : AVATAR_MIN_ROTATION_DOT;
for (int i = 0; i < _jointData.size(); i++) { for (int i = 0; i < jointData.size(); i++) {
const JointData& data = _jointData[i]; const JointData& data = jointData[i];
const JointData& last = lastSentJointData[i]; const JointData& last = lastSentJointData[i];
if (!data.rotationIsDefaultPose) { if (!data.rotationIsDefaultPose) {
bool mustSend = sendAll || last.rotationIsDefaultPose; bool mustSend = sendAll || last.rotationIsDefaultPose;
if (mustSend || last.rotation != data.rotation) { if (mustSend || last.rotation != data.rotation) {
bool largeEnoughRotation = true; // The dot product for larger rotations is a lower number.
if (cullSmallChanges) { // So if the dot() is less than the value, then the rotation is a larger angle of rotation
// The dot product for smaller rotations is a smaller number. if (!cullSmallChanges || fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT) {
// So if the dot() is less than the value, then the rotation is a larger angle of rotation
largeEnoughRotation = fabsf(glm::dot(last.rotation, data.rotation)) < minRotationDOT;
}
if (mustSend || !cullSmallChanges || largeEnoughRotation) {
validity |= (1 << validityBit); validity |= (1 << validityBit);
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
rotationSentCount++; rotationSentCount++;
@ -647,17 +625,17 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
destinationBuffer += numValidityBytes; // Move pointer past the validity bytes destinationBuffer += numValidityBytes; // Move pointer past the validity bytes
float minTranslation = !distanceAdjust ? AVATAR_MIN_TRANSLATION : getDistanceBasedMinTranslationDistance(viewerPosition); float minTranslation = (distanceAdjust && cullSmallChanges) ? getDistanceBasedMinTranslationDistance(viewerPosition) : AVATAR_MIN_ROTATION_DOT;
float maxTranslationDimension = 0.0; float maxTranslationDimension = 0.0;
for (int i = 0; i < _jointData.size(); i++) { for (int i = 0; i < jointData.size(); i++) {
const JointData& data = _jointData[i]; const JointData& data = jointData[i];
const JointData& last = lastSentJointData[i]; const JointData& last = lastSentJointData[i];
if (!data.translationIsDefaultPose) { if (!data.translationIsDefaultPose) {
bool mustSend = sendAll || last.translationIsDefaultPose; bool mustSend = sendAll || last.translationIsDefaultPose;
if (mustSend || last.translation != data.translation) { if (mustSend || last.translation != data.translation) {
if (mustSend || !cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) { if (!cullSmallChanges || glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation) {
validity |= (1 << validityBit); validity |= (1 << validityBit);
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
translationSentCount++; translationSentCount++;
@ -707,34 +685,12 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix); glm::vec3 mouseFarGrabPosition = extractTranslation(mouseFarGrabMatrix);
glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix); glm::quat mouseFarGrabRotation = extractRotation(mouseFarGrabMatrix);
data->leftFarGrabPosition[0] = leftFarGrabPosition.x; AVATAR_MEMCPY(leftFarGrabPosition);
data->leftFarGrabPosition[1] = leftFarGrabPosition.y; AVATAR_MEMCPY(leftFarGrabRotation);
data->leftFarGrabPosition[2] = leftFarGrabPosition.z; AVATAR_MEMCPY(rightFarGrabPosition);
AVATAR_MEMCPY(rightFarGrabRotation);
data->leftFarGrabRotation[0] = leftFarGrabRotation.w; AVATAR_MEMCPY(mouseFarGrabPosition);
data->leftFarGrabRotation[1] = leftFarGrabRotation.x; AVATAR_MEMCPY(mouseFarGrabRotation);
data->leftFarGrabRotation[2] = leftFarGrabRotation.y;
data->leftFarGrabRotation[3] = leftFarGrabRotation.z;
data->rightFarGrabPosition[0] = rightFarGrabPosition.x;
data->rightFarGrabPosition[1] = rightFarGrabPosition.y;
data->rightFarGrabPosition[2] = rightFarGrabPosition.z;
data->rightFarGrabRotation[0] = rightFarGrabRotation.w;
data->rightFarGrabRotation[1] = rightFarGrabRotation.x;
data->rightFarGrabRotation[2] = rightFarGrabRotation.y;
data->rightFarGrabRotation[3] = rightFarGrabRotation.z;
data->mouseFarGrabPosition[0] = mouseFarGrabPosition.x;
data->mouseFarGrabPosition[1] = mouseFarGrabPosition.y;
data->mouseFarGrabPosition[2] = mouseFarGrabPosition.z;
data->mouseFarGrabRotation[0] = mouseFarGrabRotation.w;
data->mouseFarGrabRotation[1] = mouseFarGrabRotation.x;
data->mouseFarGrabRotation[2] = mouseFarGrabRotation.y;
data->mouseFarGrabRotation[3] = mouseFarGrabRotation.z;
destinationBuffer += sizeof(AvatarDataPacket::FarGrabJoints);
int numBytes = destinationBuffer - startSection; int numBytes = destinationBuffer - startSection;
@ -764,8 +720,8 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
if (sentJointDataOut) { if (sentJointDataOut) {
// Mark default poses in lastSentJointData, so when they become non-default we send them. // Mark default poses in lastSentJointData, so when they become non-default we send them.
for (int i = 0; i < _jointData.size(); i++) { for (int i = 0; i < jointData.size(); i++) {
const JointData& data = _jointData[i]; const JointData& data = jointData[i];
JointData& local = localSentJointDataOut[i]; JointData& local = localSentJointDataOut[i];
if (data.rotationIsDefaultPose) { if (data.rotationIsDefaultPose) {
local.rotationIsDefaultPose = true; local.rotationIsDefaultPose = true;
@ -778,30 +734,31 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
// Push new sent joint data to sentJointDataOut // Push new sent joint data to sentJointDataOut
sentJointDataOut->swap(localSentJointDataOut); sentJointDataOut->swap(localSentJointDataOut);
} }
}
if (hasJointDefaultPoseFlags) { // Always true, currently:
auto startSection = destinationBuffer; if (hasJointDefaultPoseFlags) {
QReadLocker readLock(&_jointDataLock); auto startSection = destinationBuffer;
// write numJoints // write numJoints
int numJoints = _jointData.size(); int numJoints = jointData.size();
*destinationBuffer++ = (uint8_t)numJoints; *destinationBuffer++ = (uint8_t)numJoints;
// write rotationIsDefaultPose bits // write rotationIsDefaultPose bits
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) { destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
return _jointData[i].rotationIsDefaultPose; return jointData[i].rotationIsDefaultPose;
}); });
// write translationIsDefaultPose bits // write translationIsDefaultPose bits
destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) { destinationBuffer += writeBitVector(destinationBuffer, numJoints, [&](int i) {
return _jointData[i].translationIsDefaultPose; return jointData[i].translationIsDefaultPose;
}); });
if (outboundDataRateOut) { if (outboundDataRateOut) {
size_t numBytes = destinationBuffer - startSection; size_t numBytes = destinationBuffer - startSection;
outboundDataRateOut->jointDefaultPoseFlagsRate.increment(numBytes); outboundDataRateOut->jointDefaultPoseFlagsRate.increment(numBytes);
}
} }
} }
int avatarDataSize = destinationBuffer - startPosition; int avatarDataSize = destinationBuffer - startPosition;