Merge pull request #1173 from ZappoMan/bugfixes

Fix FPS stutter on rotating in place
This commit is contained in:
Philip Rosedale 2013-11-04 10:09:25 -08:00
commit a57f13e78d
6 changed files with 300 additions and 101 deletions

View file

@ -144,6 +144,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
_packetsPerSecond(0),
_bytesPerSecond(0),
_bytesCount(0),
_recentMaxPackets(0),
_resetRecentMaxPacketsSoon(true),
_swatch(NULL),
_pasteMode(false)
{
@ -1304,7 +1306,10 @@ static glm::vec3 getFaceVector(BoxFace face) {
}
void Application::idle() {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
// Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
// details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing
// details normally.
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
PerformanceWarning warn(showWarnings, "Application::idle()");
timeval check;
@ -1314,22 +1319,30 @@ void Application::idle() {
double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);
if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
_glWidget->updateGL();
_lastTimeUpdated = check;
_idleLoopStdev.addValue(timeSinceLastUpdate);
// Record standard deviation and reset counter if needed
const int STDEV_SAMPLES = 500;
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
_idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
_idleLoopStdev.reset();
{
PerformanceWarning warn(showWarnings, "Application::idle()... update()");
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS));
}
{
PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()");
_glWidget->updateGL();
}
{
PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
_lastTimeUpdated = check;
_idleLoopStdev.addValue(timeSinceLastUpdate);
// Record standard deviation and reset counter if needed
const int STDEV_SAMPLES = 500;
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
_idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
_idleLoopStdev.reset();
}
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
idleTimer->start(2);
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
idleTimer->start(2);
}
}
}
void Application::terminate() {
@ -1776,6 +1789,8 @@ static QUuid DEFAULT_NODE_ID_REF;
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
}
@ -1907,17 +1922,13 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::
}
}
void Application::update(float deltaTime) {
void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
// tell my avatar if the mouse is being pressed...
_myAvatar.setMousePressed(_mousePressed);
// check what's under the mouse and update the mouse voxel
glm::vec3 mouseRayOrigin, mouseRayDirection;
_viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(),
_mouseY / (float)_glWidget->height(), mouseRayOrigin, mouseRayDirection);
PerformanceWarning warn(showWarnings, "Application::updateMouseRay()");
_viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(),
mouseRayOrigin, mouseRayDirection);
// adjust for mirroring
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
@ -1928,12 +1939,19 @@ void Application::update(float deltaTime) {
_viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayDirection));
}
// tell my avatar if the mouse is being pressed...
_myAvatar.setMousePressed(_mousePressed);
// tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position
_myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection);
// Set where I am looking based on my mouse ray (so that other people can see)
glm::vec3 lookAtSpot;
}
void Application::updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateFaceshift()");
// Update faceshift
_faceshift.update();
@ -1943,14 +1961,19 @@ void Application::update(float deltaTime) {
}
// if we have faceshift, use that to compute the lookat direction
glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection;
if (_faceshift.isActive()) {
lookAtRayOrigin = _myAvatar.getHead().calculateAverageEyePosition();
lookAtRayDirection = _myAvatar.getHead().getOrientation() * glm::quat(glm::radians(glm::vec3(
_faceshift.getEstimatedEyePitch(), _faceshift.getEstimatedEyeYaw(), 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f);
}
}
updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin,
glm::vec3& lookAtRayDirection) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()");
if (_lookatTargetAvatar && !_faceshift.isActive()) {
// If the mouse is over another avatar's head...
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
@ -1969,11 +1992,14 @@ void Application::update(float deltaTime) {
lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE;
_myAvatar.getHead().setLookAtPosition(lookAtSpot);
}
}
void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
float& distance, BoxFace& face) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()");
// Find the voxel we are hovering over, and respond if clicked
float distance;
BoxFace face;
// If we have clicked on a voxel, update it's color
if (_isHoverVoxelSounding) {
VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
@ -1995,23 +2021,38 @@ void Application::update(float deltaTime) {
} else {
// Check for a new hover voxel
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) {
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
_hoverVoxelOriginalColor[3] = 1;
_audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY);
_isHoverVoxelSounding = true;
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
// and make sure the tree is not already busy... because otherwise you'll have to wait.
if (!_voxels.treeIsBusy()) {
{
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
}
if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel &&
glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) {
_hoverVoxelOriginalColor[0] = _hoverVoxel.red;
_hoverVoxelOriginalColor[1] = _hoverVoxel.green;
_hoverVoxelOriginalColor[2] = _hoverVoxel.blue;
_hoverVoxelOriginalColor[3] = 1;
_audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY);
_isHoverVoxelSounding = true;
}
}
}
}
void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
float& distance, BoxFace& face) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()");
_mouseVoxel.s = 0.0f;
if (Menu::getInstance()->isVoxelModeActionChecked() &&
(fabs(_myAvatar.getVelocity().x) +
fabs(_myAvatar.getVelocity().y) +
fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) {
PerformanceWarning warn(showWarnings, "Application::update()... findRayIntersection()");
if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) {
if (distance < MAX_VOXEL_EDIT_DISTANCE) {
@ -2080,12 +2121,17 @@ void Application::update(float deltaTime) {
_justEditedVoxel = false;
}
}
}
void Application::updateHandAndTouch(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()");
// walking triggers the handControl to stop
if (_myAvatar.getMode() == AVATAR_MODE_WALKING) {
_handControl.stop();
}
// Update from Touch
if (_isTouchPressed) {
float TOUCH_YAW_SCALE = -0.25f;
@ -2096,19 +2142,29 @@ void Application::update(float deltaTime) {
_lastTouchAvgX = _touchAvgX;
_lastTouchAvgY = _touchAvgY;
}
// Leap finger-sensing device
}
void Application::updateLeap(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateLeap()");
LeapManager::enableFakeFingers(Menu::getInstance()->isOptionChecked(MenuOption::SimulateLeapHand));
_myAvatar.getHand().setRaveGloveActive(Menu::getInstance()->isOptionChecked(MenuOption::TestRaveGlove));
LeapManager::nextFrame(_myAvatar);
// Read serial port interface devices
}
void Application::updateSerialDevices(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()");
if (_serialHeadSensor.isActive()) {
_serialHeadSensor.readData(deltaTime);
}
// Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
updateAvatar(deltaTime);
}
void Application::updateThreads(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateThreads()");
// read incoming packets from network
if (!_enableNetworkThread) {
@ -2120,12 +2176,12 @@ void Application::update(float deltaTime) {
_voxelProcessor.threadRoutine();
_voxelEditSender.threadRoutine();
}
}
void Application::updateMyAvatarSimulation(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateMyAvatarSimulation()");
//loop through all the other avatars and simulate them...
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection);
// Simulate myself
if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) {
_myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition()));
}
@ -2138,12 +2194,21 @@ void Application::update(float deltaTime) {
} else {
_myAvatar.simulate(deltaTime, NULL);
}
// Simulate particle cloud movements
}
void Application::updateParticles(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateParticles()");
if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) {
_cloud.simulate(deltaTime);
}
}
void Application::updateTransmitter(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateTransmitter()");
// no transmitter drive implies transmitter pick
if (!Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
_transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position;
@ -2178,7 +2243,12 @@ void Application::update(float deltaTime) {
} else {
_transmitterPickStart = _transmitterPickEnd = glm::vec3();
}
}
void Application::updateCamera(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateCamera()");
if (!OculusManager::isConnected()) {
if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
@ -2213,7 +2283,12 @@ void Application::update(float deltaTime) {
}
}
}
}
void Application::updateDialogs(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateDialogs()");
// Update bandwidth dialog, if any
BandwidthDialog* bandwidthDialog = Menu::getInstance()->getBandwidthDialog();
if (bandwidthDialog) {
@ -2224,6 +2299,11 @@ void Application::update(float deltaTime) {
if (voxelStatsDialog) {
voxelStatsDialog->update();
}
}
void Application::updateAudio(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateAudio()");
// Update audio stats for procedural sounds
#ifndef _WIN32
@ -2231,7 +2311,12 @@ void Application::update(float deltaTime) {
_audio.setLastVelocity(_myAvatar.getVelocity());
_audio.eventuallyAnalyzePing();
#endif
}
void Application::updateCursor(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateCursor()");
// watch mouse position, if it hasn't moved, hide the cursor
bool underMouse = _glWidget->underMouse();
if (!_mouseHidden) {
@ -2252,6 +2337,43 @@ void Application::update(float deltaTime) {
}
}
void Application::update(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
// check what's under the mouse and update the mouse voxel
glm::vec3 mouseRayOrigin, mouseRayDirection;
updateMouseRay(deltaTime, mouseRayOrigin, mouseRayDirection);
// Set where I am looking based on my mouse ray (so that other people can see)
glm::vec3 lookAtSpot;
glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection;
updateFaceshift(deltaTime, mouseRayOrigin, mouseRayDirection, lookAtRayOrigin, lookAtRayDirection);
updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot);
updateMyAvatarLookAtPosition(lookAtSpot, lookAtRayOrigin, lookAtRayDirection);
// Find the voxel we are hovering over, and respond if clicked
float distance;
BoxFace face;
updateHoverVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // clicking on voxels and making sounds
updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels
updateHandAndTouch(deltaTime); // Update state for touch sensors
updateLeap(deltaTime); // Leap finger-sensing device
updateSerialDevices(deltaTime); // Read serial port interface devices
updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them...
updateMyAvatarSimulation(deltaTime); // Simulate myself
updateParticles(deltaTime); // Simulate particle cloud movements
updateTransmitter(deltaTime); // transmitter drive or pick
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
updateDialogs(deltaTime); // update various stats dialogs if present
updateAudio(deltaTime); // Update audio stats for procedural sounds
updateCursor(deltaTime); // Handle cursor updates
}
void Application::updateAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateAvatar()");
@ -3258,6 +3380,8 @@ void Application::displayStats() {
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats);
QLocale locale(QLocale::English);
std::stringstream voxelStats;
voxelStats.precision(4);
voxelStats << "Voxels " <<
@ -3280,11 +3404,19 @@ void Application::displayStats() {
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
unsigned long localTotal = VoxelNode::getNodeCount();
unsigned long localInternal = VoxelNode::getInternalNodeCount();
unsigned long localLeaves = VoxelNode::getLeafNodeCount();
QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' ');
QString localInternalString = locale.toString((uint)localInternal);
QString localLeavesString = locale.toString((uint)localLeaves);
voxelStats.str("");
voxelStats <<
"Local Voxels Total: " << VoxelNode::getNodeCount() << ", " <<
"Internal: " << VoxelNode::getInternalNodeCount() << " , " <<
"Leaves: " << VoxelNode::getLeafNodeCount() << "";
"Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " <<
"Internal: " << localInternalString.toLocal8Bit().constData() << " / " <<
"Leaves: " << localLeavesString.toLocal8Bit().constData() << "";
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
@ -3311,6 +3443,29 @@ void Application::displayStats() {
voxelStats << "Sending Mode: " << voxelDetails;
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
voxelStats.str("");
int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
QString packetsString = locale.toString((int)voxelPacketsToProcess);
QString maxString = locale.toString((int)_recentMaxPackets);
voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData()
<< " [Recent Max: " << maxString.toLocal8Bit().constData() << "]";
if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
_recentMaxPackets = 0;
_resetRecentMaxPacketsSoon = false;
}
if (voxelPacketsToProcess == 0) {
_resetRecentMaxPacketsSoon = true;
} else {
if (voxelPacketsToProcess > _recentMaxPackets) {
_recentMaxPackets = voxelPacketsToProcess;
}
}
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
char avatarMixerStats[200];

View file

@ -223,9 +223,30 @@ private:
void init();
void update(float deltaTime);
// Various helper functions called during update()
void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection);
void updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection);
void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection);
void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
float& distance, BoxFace& face);
void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
float& distance, BoxFace& face);
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition);
void updateHandAndTouch(float deltaTime);
void updateLeap(float deltaTime);
void updateSerialDevices(float deltaTime);
void updateThreads(float deltaTime);
void updateMyAvatarSimulation(float deltaTime);
void updateParticles(float deltaTime);
void updateTransmitter(float deltaTime);
void updateCamera(float deltaTime);
void updateDialogs(float deltaTime);
void updateAudio(float deltaTime);
void updateCursor(float deltaTime);
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
glm::vec3& eyePosition, QUuid &nodeUUID);
bool isLookingAtMyAvatar(Avatar* avatar);
@ -407,6 +428,9 @@ private:
int _bytesPerSecond;
int _bytesCount;
int _recentMaxPackets; // recent max incoming voxel packets to process
bool _resetRecentMaxPacketsSoon;
StDev _idleLoopStdev;
float _idleLoopMeasuredJitter;

View file

@ -19,7 +19,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
"VoxelPacketProcessor::processPacket()");
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount());
}
ssize_t messageLength = packetLength;

View file

@ -110,6 +110,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_culledOnce = false;
_inhideOutOfView = false;
_treeIsBusy = false;
}
void VoxelSystem::voxelDeleted(VoxelNode* node) {
@ -595,9 +596,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
"readBitstreamToTree()");
// ask the VoxelTree to read the bitstream into the tree
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
pthread_mutex_unlock(&_treeLock);
unlockTree();
}
break;
case PACKET_TYPE_VOXEL_DATA_MONOCHROME: {
@ -605,9 +606,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
"readBitstreamToTree()");
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
pthread_mutex_unlock(&_treeLock);
unlockTree();
}
break;
case PACKET_TYPE_Z_COMMAND:
@ -1002,7 +1003,9 @@ int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool force
// not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality
// possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
// state actually occurs.
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) {
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
}
return 0;
}
@ -1405,9 +1408,9 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
int VoxelSystem::_nodeCount = 0;
void VoxelSystem::killLocalVoxels() {
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->eraseAllVoxels();
pthread_mutex_unlock(&_treeLock);
unlockTree();
clearFreeBufferIndexes();
_voxelsInReadArrays = 0; // do we need to do this?
setupNewVoxelsForDrawing();
@ -1426,9 +1429,9 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extra
void VoxelSystem::clearAllNodesBufferIndex() {
_nodeCount = 0;
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation);
pthread_mutex_unlock(&_treeLock);
unlockTree();
if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug("clearing buffer index of %d nodes\n", _nodeCount);
}
@ -1882,7 +1885,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
_inhideOutOfView = true;
bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails);
PerformanceWarning warn(showDebugDetails, "hideOutOfView()");
bool widenFrustum = true;
// When using "delta" view frustums and only hide/show items that are in the difference
@ -1916,9 +1919,9 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
return;
}
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
pthread_mutex_unlock(&_treeLock);
unlockTree();
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable
_culledOnce = true;
@ -1927,7 +1930,8 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) {
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
}
if (showDebugDetails) {
bool extraDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging);
if (extraDebugDetails) {
qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n",
args.nodesScanned, args.nodesRemoved, args.nodesInside,
args.nodesIntersect, args.nodesOutside
@ -2106,10 +2110,10 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) {
bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
VoxelDetail& detail, float& distance, BoxFace& face) {
pthread_mutex_lock(&_treeLock);
lockTree();
VoxelNode* node;
if (!_tree->findRayIntersection(origin, direction, node, distance, face)) {
pthread_mutex_unlock(&_treeLock);
unlockTree();
return false;
}
detail.x = node->getCorner().x;
@ -2119,21 +2123,21 @@ bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3&
detail.red = node->getColor()[0];
detail.green = node->getColor()[1];
detail.blue = node->getColor()[2];
pthread_mutex_unlock(&_treeLock);
unlockTree();
return true;
}
bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) {
pthread_mutex_lock(&_treeLock);
lockTree();
bool result = _tree->findSpherePenetration(center, radius, penetration);
pthread_mutex_unlock(&_treeLock);
unlockTree();
return result;
}
bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) {
pthread_mutex_lock(&_treeLock);
lockTree();
bool result = _tree->findCapsulePenetration(start, end, radius, penetration);
pthread_mutex_unlock(&_treeLock);
unlockTree();
return result;
}
@ -2307,9 +2311,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() {
void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) {
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->deleteVoxelAt(x, y, z, s);
pthread_mutex_unlock(&_treeLock);
unlockTree();
// redraw!
setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in?
@ -2324,9 +2328,9 @@ void VoxelSystem::createVoxel(float x, float y, float z, float s,
unsigned char red, unsigned char green, unsigned char blue, bool destructive) {
//qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s);
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->createVoxel(x, y, z, s, red, green, blue, destructive);
pthread_mutex_unlock(&_treeLock);
unlockTree();
setupNewVoxelsForDrawing();
};
@ -2649,9 +2653,9 @@ void VoxelSystem::nodeKilled(Node* node) {
if (_voxelServerCount > 0) {
// Kill any voxels from the local tree that match this nodeID
// commenting out for removal of 16 bit node IDs
pthread_mutex_lock(&_treeLock);
lockTree();
_tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID);
pthread_mutex_unlock(&_treeLock);
unlockTree();
_tree->setDirtyBit();
setupNewVoxelsForDrawing();
} else {
@ -2719,5 +2723,15 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() {
return (_initialMemoryUsageGPU - currentFreeMemory);
}
void VoxelSystem::lockTree() {
pthread_mutex_lock(&_treeLock);
_treeIsBusy = true;
}
void VoxelSystem::unlockTree() {
_treeIsBusy = false;
pthread_mutex_unlock(&_treeLock);
}

View file

@ -120,6 +120,8 @@ public:
virtual void nodeKilled(Node* node);
virtual void domainChanged(QString domain);
bool treeIsBusy() const { return _treeIsBusy; }
signals:
void importSize(float x, float y, float z);
void importProgress(int progress);
@ -302,6 +304,10 @@ private:
bool _useFastVoxelPipeline;
bool _inhideOutOfView;
bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree
void lockTree();
void unlockTree();
};
#endif

View file

@ -24,6 +24,12 @@ public:
/// \param ssize_t packetLength size of received data
/// \thread network receive thread
void queueReceivedPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength);
/// Are there received packets waiting to be processed
bool hasPacketsToProcess() const { return _packets.size() > 0; }
/// How many received packets waiting are to be processed
int packetsToProcessCount() const { return _packets.size(); }
protected:
/// Callback for processing of recieved packets. Implement this to process the incoming packets.
@ -36,12 +42,6 @@ protected:
/// Implements generic processing behavior for this thread.
virtual bool process();
/// Are there received packets waiting to be processed
bool hasPacketsToProcess() const { return _packets.size() > 0; }
/// How many received packets waiting are to be processed
int packetsToProcessCount() const { return _packets.size(); }
private:
std::vector<NetworkPacket> _packets;