Merge branch 'master' of github.com:highfidelity/hifi into fix-logging-crash

This commit is contained in:
Seth Alves 2016-03-25 16:17:58 -07:00
commit 1532800a4e
31 changed files with 962 additions and 711 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 KiB

After

Width:  |  Height:  |  Size: 51 KiB

View file

@ -240,25 +240,26 @@ class DeadlockWatchdogThread : public QThread {
public: public:
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 15 * USECS_PER_SECOND; static const unsigned long HEARTBEAT_REPORT_INTERVAL_USECS = 5 * USECS_PER_SECOND;
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 30 * USECS_PER_SECOND;
static const int WARNING_ELAPSED_HEARTBEAT = 500 * USECS_PER_MSEC; // warn if elapsed heartbeat average is large
static const int HEARTBEAT_SAMPLES = 100000; // ~5 seconds worth of samples
// Set the heartbeat on launch // Set the heartbeat on launch
DeadlockWatchdogThread() { DeadlockWatchdogThread() {
setObjectName("Deadlock Watchdog"); setObjectName("Deadlock Watchdog");
QTimer* heartbeatTimer = new QTimer();
// Give the heartbeat an initial value // Give the heartbeat an initial value
updateHeartbeat(); _heartbeat = usecTimestampNow();
connect(heartbeatTimer, &QTimer::timeout, [this] {
updateHeartbeat();
});
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
connect(qApp, &QCoreApplication::aboutToQuit, [this] { connect(qApp, &QCoreApplication::aboutToQuit, [this] {
_quit = true; _quit = true;
}); });
} }
void updateHeartbeat() { void updateHeartbeat() {
_heartbeat = usecTimestampNow(); auto now = usecTimestampNow();
auto elapsed = now - _heartbeat;
_movingAverage.addSample(elapsed);
_heartbeat = now;
} }
void deadlockDetectionCrash() { void deadlockDetectionCrash() {
@ -269,10 +270,52 @@ public:
void run() override { void run() override {
while (!_quit) { while (!_quit) {
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
#ifdef NDEBUG
auto now = usecTimestampNow(); auto now = usecTimestampNow();
auto lastHeartbeatAge = now - _heartbeat;
// in the unlikely event that now is less than _heartbeat, don't rollover and confuse ourselves
auto lastHeartbeatAge = (now > _heartbeat) ? now - _heartbeat : 0;
auto sinceLastReport = (now > _lastReport) ? now - _lastReport : 0;
auto elapsedMovingAverage = _movingAverage.getAverage();
if (elapsedMovingAverage > _maxElapsedAverage) {
qDebug() << "DEADLOCK WATCHDOG NEW maxElapsedAverage:"
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "maxElapsed:" << _maxElapsed
<< "PREVIOUS maxElapsedAverage:" << _maxElapsedAverage
<< "NEW maxElapsedAverage:" << elapsedMovingAverage
<< "samples:" << _movingAverage.getSamples();
_maxElapsedAverage = elapsedMovingAverage;
}
if (lastHeartbeatAge > _maxElapsed) {
qDebug() << "DEADLOCK WATCHDOG NEW maxElapsed:"
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "PREVIOUS maxElapsed:" << _maxElapsed
<< "NEW maxElapsed:" << lastHeartbeatAge
<< "maxElapsedAverage:" << _maxElapsedAverage
<< "samples:" << _movingAverage.getSamples();
_maxElapsed = lastHeartbeatAge;
}
if ((sinceLastReport > HEARTBEAT_REPORT_INTERVAL_USECS) || (elapsedMovingAverage > WARNING_ELAPSED_HEARTBEAT)) {
qDebug() << "DEADLOCK WATCHDOG STATUS -- lastHeartbeatAge:" << lastHeartbeatAge
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "maxElapsed:" << _maxElapsed
<< "maxElapsedAverage:" << _maxElapsedAverage
<< "samples:" << _movingAverage.getSamples();
_lastReport = now;
}
#ifdef NDEBUG
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
qDebug() << "DEADLOCK DETECTED -- "
<< "lastHeartbeatAge:" << lastHeartbeatAge
<< "[ _heartbeat:" << _heartbeat
<< "now:" << now << " ]"
<< "elapsedMovingAverage:" << elapsedMovingAverage
<< "maxElapsed:" << _maxElapsed
<< "maxElapsedAverage:" << _maxElapsedAverage
<< "samples:" << _movingAverage.getSamples();
deadlockDetectionCrash(); deadlockDetectionCrash();
} }
#endif #endif
@ -280,10 +323,19 @@ public:
} }
static std::atomic<uint64_t> _heartbeat; static std::atomic<uint64_t> _heartbeat;
static std::atomic<uint64_t> _lastReport;
static std::atomic<uint64_t> _maxElapsed;
static std::atomic<int> _maxElapsedAverage;
static ThreadSafeMovingAverage<int, HEARTBEAT_SAMPLES> _movingAverage;
bool _quit { false }; bool _quit { false };
}; };
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat; std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
std::atomic<uint64_t> DeadlockWatchdogThread::_lastReport;
std::atomic<uint64_t> DeadlockWatchdogThread::_maxElapsed;
std::atomic<int> DeadlockWatchdogThread::_maxElapsedAverage;
ThreadSafeMovingAverage<int, DeadlockWatchdogThread::HEARTBEAT_SAMPLES> DeadlockWatchdogThread::_movingAverage;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
class MyNativeEventFilter : public QAbstractNativeEventFilter { class MyNativeEventFilter : public QAbstractNativeEventFilter {
@ -1381,6 +1433,8 @@ void Application::initializeUi() {
void Application::paintGL() { void Application::paintGL() {
updateHeartbeat();
// Some plugins process message events, potentially leading to // Some plugins process message events, potentially leading to
// re-entering a paint event. don't allow further processing if this // re-entering a paint event. don't allow further processing if this
// happens // happens
@ -2502,6 +2556,8 @@ static uint32_t _renderedFrameIndex { INVALID_FRAME };
void Application::idle(uint64_t now) { void Application::idle(uint64_t now) {
updateHeartbeat();
if (_aboutToQuit || _inPaint) { if (_aboutToQuit || _inPaint) {
return; // bail early, nothing to do here. return; // bail early, nothing to do here.
} }

View file

@ -611,7 +611,7 @@ AnimNode::Pointer AnimNodeLoader::load(const QByteArray& contents, const QUrl& j
return loadNode(rootVal.toObject(), jsonUrl); return loadNode(rootVal.toObject(), jsonUrl);
} }
void AnimNodeLoader::onRequestDone(const QByteArray& data) { void AnimNodeLoader::onRequestDone(const QByteArray data) {
auto node = load(data, _url); auto node = load(data, _url);
if (node) { if (node) {
emit success(node); emit success(node);

View file

@ -36,7 +36,7 @@ protected:
static AnimNode::Pointer load(const QByteArray& contents, const QUrl& jsonUrl); static AnimNode::Pointer load(const QByteArray& contents, const QUrl& jsonUrl);
protected slots: protected slots:
void onRequestDone(const QByteArray& data); void onRequestDone(const QByteArray data);
void onRequestError(QNetworkReply::NetworkError error); void onRequestError(QNetworkReply::NetworkError error);
protected: protected:

View file

@ -354,7 +354,9 @@ void RenderableModelEntityItem::updateModelBounds() {
bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
if ((movingOrAnimating || if ((movingOrAnimating ||
_needsInitialSimulation || _needsInitialSimulation ||
_needsJointSimulation ||
_model->getTranslation() != getPosition() || _model->getTranslation() != getPosition() ||
_model->getScaleToFitDimensions() != getDimensions() ||
_model->getRotation() != getRotation() || _model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint()) _model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) { && _model->isActive() && _dimensionsInitialized) {
@ -370,6 +372,7 @@ void RenderableModelEntityItem::updateModelBounds() {
} }
_needsInitialSimulation = false; _needsInitialSimulation = false;
_needsJointSimulation = false;
} }
} }
@ -770,6 +773,7 @@ bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index,
_absoluteJointRotationsInObjectFrameSet[index] = true; _absoluteJointRotationsInObjectFrameSet[index] = true;
_absoluteJointRotationsInObjectFrameDirty[index] = true; _absoluteJointRotationsInObjectFrameDirty[index] = true;
result = true; result = true;
_needsJointSimulation = true;
} }
}); });
return result; return result;
@ -785,11 +789,33 @@ bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int ind
_absoluteJointTranslationsInObjectFrameSet[index] = true; _absoluteJointTranslationsInObjectFrameSet[index] = true;
_absoluteJointTranslationsInObjectFrameDirty[index] = true; _absoluteJointTranslationsInObjectFrameDirty[index] = true;
result = true; result = true;
_needsJointSimulation = true;
} }
}); });
return result; return result;
} }
void RenderableModelEntityItem::setJointRotations(const QVector<glm::quat>& rotations) {
ModelEntityItem::setJointRotations(rotations);
_needsJointSimulation = true;
}
void RenderableModelEntityItem::setJointRotationsSet(const QVector<bool>& rotationsSet) {
ModelEntityItem::setJointRotationsSet(rotationsSet);
_needsJointSimulation = true;
}
void RenderableModelEntityItem::setJointTranslations(const QVector<glm::vec3>& translations) {
ModelEntityItem::setJointTranslations(translations);
_needsJointSimulation = true;
}
void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& translationsSet) {
ModelEntityItem::setJointTranslationsSet(translationsSet);
_needsJointSimulation = true;
}
void RenderableModelEntityItem::locationChanged() { void RenderableModelEntityItem::locationChanged() {
EntityItem::locationChanged(); EntityItem::locationChanged();
if (_model && _model->isActive()) { if (_model && _model->isActive()) {

View file

@ -69,6 +69,11 @@ public:
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override; virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override;
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override; virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override;
virtual void setJointRotations(const QVector<glm::quat>& rotations) override;
virtual void setJointRotationsSet(const QVector<bool>& rotationsSet) override;
virtual void setJointTranslations(const QVector<glm::vec3>& translations) override;
virtual void setJointTranslationsSet(const QVector<bool>& translationsSet) override;
virtual void loader() override; virtual void loader() override;
virtual void locationChanged() override; virtual void locationChanged() override;
@ -97,6 +102,8 @@ private:
bool _showCollisionHull = false; bool _showCollisionHull = false;
bool getAnimationFrame(); bool getAnimationFrame();
bool _needsJointSimulation { false };
}; };
#endif // hifi_RenderableModelEntityItem_h #endif // hifi_RenderableModelEntityItem_h

File diff suppressed because it is too large Load diff

View file

@ -48,6 +48,8 @@ public:
virtual ~RenderablePolyVoxEntityItem(); virtual ~RenderablePolyVoxEntityItem();
void initializePolyVox();
virtual void somethingChangedNotification() { virtual void somethingChangedNotification() {
// This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing // This gets called from EnityItem::readEntityDataFromBuffer every time a packet describing
// this entity comes from the entity-server. It gets called even if nothing has actually changed // this entity comes from the entity-server. It gets called even if nothing has actually changed
@ -114,17 +116,28 @@ public:
virtual void setYPNeighborID(const EntityItemID& yPNeighborID); virtual void setYPNeighborID(const EntityItemID& yPNeighborID);
virtual void setZPNeighborID(const EntityItemID& zPNeighborID); virtual void setZPNeighborID(const EntityItemID& zPNeighborID);
virtual void rebakeMesh();
virtual void updateRegistrationPoint(const glm::vec3& value); virtual void updateRegistrationPoint(const glm::vec3& value);
void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize);
void forEachVoxelValue(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize,
std::function<void(int, int, int, uint8_t)> thunk);
void setMesh(model::MeshPointer mesh);
void setCollisionPoints(const QVector<QVector<glm::vec3>> points, AABox box);
PolyVox::SimpleVolume<uint8_t>* getVolData() { return _volData; }
uint8_t getVoxelInternal(int x, int y, int z);
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; }); }
private: private:
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions // The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
// may not match _voxelVolumeSize. // may not match _voxelVolumeSize.
model::MeshPointer _mesh; model::MeshPointer _mesh;
bool _meshDirty; // does collision-shape need to be recomputed? bool _meshDirty { true }; // does collision-shape need to be recomputed?
mutable QReadWriteLock _meshLock{QReadWriteLock::Recursive}; bool _meshInitialized { false };
NetworkTexturePointer _xTexture; NetworkTexturePointer _xTexture;
NetworkTexturePointer _yTexture; NetworkTexturePointer _yTexture;
@ -135,44 +148,35 @@ private:
static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _pipeline;
ShapeInfo _shapeInfo; ShapeInfo _shapeInfo;
mutable QReadWriteLock _shapeInfoLock;
PolyVox::SimpleVolume<uint8_t>* _volData = nullptr; PolyVox::SimpleVolume<uint8_t>* _volData = nullptr;
mutable QReadWriteLock _volDataLock{QReadWriteLock::Recursive}; // lock for _volData
bool _volDataDirty = false; // does getMesh need to be called? bool _volDataDirty = false; // does getMesh need to be called?
int _onCount; // how many non-zero voxels are in _volData int _onCount; // how many non-zero voxels are in _volData
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle, bool _neighborsNeedUpdate { false };
int x, int y, int z) const;
uint8_t getVoxelInternal(int x, int y, int z);
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
bool updateOnCount(int x, int y, int z, uint8_t toValue); bool updateOnCount(int x, int y, int z, uint8_t toValue);
PolyVox::RaycastResult doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, glm::vec4& result) const; PolyVox::RaycastResult doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, glm::vec4& result) const;
// these are run off the main thread // these are run off the main thread
void decompressVolumeData(); void decompressVolumeData();
void decompressVolumeDataAsync();
void compressVolumeDataAndSendEditPacket(); void compressVolumeDataAndSendEditPacket();
void compressVolumeDataAndSendEditPacketAsync(); virtual void getMesh(); // recompute mesh
void getMesh();
void getMeshAsync();
void computeShapeInfoWorker(); void computeShapeInfoWorker();
void computeShapeInfoWorkerAsync();
QSemaphore _threadRunning{1};
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID // these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
EntityItemWeakPointer _xNNeighbor; // neighor found by going along negative X axis EntityItemWeakPointer _xNNeighbor; // neighbor found by going along negative X axis
EntityItemWeakPointer _yNNeighbor; EntityItemWeakPointer _yNNeighbor;
EntityItemWeakPointer _zNNeighbor; EntityItemWeakPointer _zNNeighbor;
EntityItemWeakPointer _xPNeighbor; // neighor found by going along positive X axis EntityItemWeakPointer _xPNeighbor; // neighbor found by going along positive X axis
EntityItemWeakPointer _yPNeighbor; EntityItemWeakPointer _yPNeighbor;
EntityItemWeakPointer _zPNeighbor; EntityItemWeakPointer _zPNeighbor;
void clearOutOfDateNeighbors();
void cacheNeighbors(); void cacheNeighbors();
void copyUpperEdgesFromNeighbors(); void copyUpperEdgesFromNeighbors();
void bonkNeighbors(); void bonkNeighbors();
}; };
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z);
#endif // hifi_RenderablePolyVoxEntityItem_h #endif // hifi_RenderablePolyVoxEntityItem_h

View file

@ -101,12 +101,15 @@ void EntitySimulation::expireMortalEntities(const quint64& now) {
prepareEntityForDelete(entity); prepareEntityForDelete(entity);
} else { } else {
if (expiry < _nextExpiry) { if (expiry < _nextExpiry) {
// remeber the smallest _nextExpiry so we know when to start the next search // remember the smallest _nextExpiry so we know when to start the next search
_nextExpiry = expiry; _nextExpiry = expiry;
} }
++itemItr; ++itemItr;
} }
} }
if (_mortalEntities.size() < 1) {
_nextExpiry = -1;
}
} }
} }

View file

@ -120,10 +120,10 @@ public:
virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); } virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); }
virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); } virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); }
void setJointRotations(const QVector<glm::quat>& rotations); virtual void setJointRotations(const QVector<glm::quat>& rotations);
void setJointRotationsSet(const QVector<bool>& rotationsSet); virtual void setJointRotationsSet(const QVector<bool>& rotationsSet);
void setJointTranslations(const QVector<glm::vec3>& translations); virtual void setJointTranslations(const QVector<glm::vec3>& translations);
void setJointTranslationsSet(const QVector<bool>& translationsSet); virtual void setJointTranslationsSet(const QVector<bool>& translationsSet);
QVector<glm::quat> getJointRotations() const; QVector<glm::quat> getJointRotations() const;
QVector<bool> getJointRotationsSet() const; QVector<bool> getJointRotationsSet() const;
QVector<glm::vec3> getJointTranslations() const; QVector<glm::vec3> getJointTranslations() const;

View file

@ -64,44 +64,47 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID) :
} }
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
QWriteLocker(&this->_voxelDataLock); withWriteLock([&] {
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x); _voxelVolumeSize = glm::vec3(roundf(voxelVolumeSize.x), roundf(voxelVolumeSize.y), roundf(voxelVolumeSize.z));
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y); if (_voxelVolumeSize.x < 1) {
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z); qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1";
_voxelVolumeSize.x = 1;
}
if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max";
_voxelVolumeSize.x = MAX_VOXEL_DIMENSION;
}
_voxelVolumeSize = glm::vec3(roundf(voxelVolumeSize.x), roundf(voxelVolumeSize.y), roundf(voxelVolumeSize.z)); if (_voxelVolumeSize.y < 1) {
if (_voxelVolumeSize.x < 1) { qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1";
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to 1"; _voxelVolumeSize.y = 1;
_voxelVolumeSize.x = 1; }
} if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) {
if (_voxelVolumeSize.x > MAX_VOXEL_DIMENSION) { qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max";
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping x of" << _voxelVolumeSize.x << "to max"; _voxelVolumeSize.y = MAX_VOXEL_DIMENSION;
_voxelVolumeSize.x = MAX_VOXEL_DIMENSION; }
}
if (_voxelVolumeSize.y < 1) { if (_voxelVolumeSize.z < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to 1"; qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
_voxelVolumeSize.y = 1; _voxelVolumeSize.z = 1;
} }
if (_voxelVolumeSize.y > MAX_VOXEL_DIMENSION) { if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping y of" << _voxelVolumeSize.y << "to max"; qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
_voxelVolumeSize.y = MAX_VOXEL_DIMENSION; _voxelVolumeSize.z = MAX_VOXEL_DIMENSION;
} }
});
if (_voxelVolumeSize.z < 1) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to 1";
_voxelVolumeSize.z = 1;
}
if (_voxelVolumeSize.z > MAX_VOXEL_DIMENSION) {
qDebug() << "PolyVoxEntityItem::setVoxelVolumeSize clamping z of" << _voxelVolumeSize.z << "to max";
_voxelVolumeSize.z = MAX_VOXEL_DIMENSION;
}
} }
const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const { glm::vec3 PolyVoxEntityItem::getVoxelVolumeSize() const {
QWriteLocker locker(&this->_voxelDataLock); glm::vec3 voxelVolumeSize;
return _voxelVolumeSize; withReadLock([&] {
voxelVolumeSize = _voxelVolumeSize;
});
return voxelVolumeSize;
} }
@ -226,12 +229,16 @@ void PolyVoxEntityItem::debugDump() const {
} }
void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) { void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
QWriteLocker(&this->_voxelDataLock); withWriteLock([&] {
_voxelData = voxelData; _voxelData = voxelData;
_voxelDataDirty = true; _voxelDataDirty = true;
});
} }
const QByteArray PolyVoxEntityItem::getVoxelData() const { const QByteArray PolyVoxEntityItem::getVoxelData() const {
QReadLocker(&this->_voxelDataLock); QByteArray voxelDataCopy;
return _voxelData; withReadLock([&] {
voxelDataCopy = _voxelData;
});
return voxelDataCopy;
} }

View file

@ -52,7 +52,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual void debugDump() const; virtual void debugDump() const;
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
virtual const glm::vec3& getVoxelVolumeSize() const; virtual glm::vec3 getVoxelVolumeSize() const;
virtual void setVoxelData(QByteArray voxelData); virtual void setVoxelData(QByteArray voxelData);
virtual const QByteArray getVoxelData() const; virtual const QByteArray getVoxelData() const;
@ -128,12 +128,14 @@ class PolyVoxEntityItem : public EntityItem {
virtual void rebakeMesh() {}; virtual void rebakeMesh() {};
void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); }
virtual void getMesh() {}; // recompute mesh
protected: protected:
glm::vec3 _voxelVolumeSize; // this is always 3 bytes glm::vec3 _voxelVolumeSize; // this is always 3 bytes
mutable QReadWriteLock _voxelDataLock;
QByteArray _voxelData; QByteArray _voxelData;
bool _voxelDataDirty; bool _voxelDataDirty; // _voxelData has changed, things that depend on it should be updated
PolyVoxSurfaceStyle _voxelSurfaceStyle; PolyVoxSurfaceStyle _voxelSurfaceStyle;

View file

@ -293,7 +293,7 @@ void NetworkGeometry::requestModel(const QUrl& url) {
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError); connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
} }
void NetworkGeometry::mappingRequestDone(const QByteArray& data) { void NetworkGeometry::mappingRequestDone(const QByteArray data) {
assert(_state == RequestMappingState); assert(_state == RequestMappingState);
// parse the mapping file // parse the mapping file
@ -325,7 +325,7 @@ void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
emit onFailure(*this, MappingRequestError); emit onFailure(*this, MappingRequestError);
} }
void NetworkGeometry::modelRequestDone(const QByteArray& data) { void NetworkGeometry::modelRequestDone(const QByteArray data) {
assert(_state == RequestModelState); assert(_state == RequestModelState);
_state = ParsingModelState; _state = ParsingModelState;

View file

@ -113,10 +113,10 @@ public slots:
void textureLoaded(const QWeakPointer<NetworkTexture>& networkTexture); void textureLoaded(const QWeakPointer<NetworkTexture>& networkTexture);
protected slots: protected slots:
void mappingRequestDone(const QByteArray& data); void mappingRequestDone(const QByteArray data);
void mappingRequestError(QNetworkReply::NetworkError error); void mappingRequestError(QNetworkReply::NetworkError error);
void modelRequestDone(const QByteArray& data); void modelRequestDone(const QByteArray data);
void modelRequestError(QNetworkReply::NetworkError error); void modelRequestError(QNetworkReply::NetworkError error);
void modelParseSuccess(FBXGeometry* geometry); void modelParseSuccess(FBXGeometry* geometry);

View file

@ -81,6 +81,8 @@ AccountManager::AccountManager() :
qRegisterMetaType<QHttpMultiPart*>("QHttpMultiPart*"); qRegisterMetaType<QHttpMultiPart*>("QHttpMultiPart*");
qRegisterMetaType<AccountManagerAuth::Type>();
connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged); connect(&_accountInfo, &DataServerAccountInfo::balanceChanged, this, &AccountManager::accountInfoBalanceChanged);
} }
@ -215,12 +217,13 @@ void AccountManager::sendRequest(const QString& path,
if (thread() != QThread::currentThread()) { if (thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "sendRequest", QMetaObject::invokeMethod(this, "sendRequest",
Q_ARG(const QString&, path), Q_ARG(const QString&, path),
Q_ARG(AccountManagerAuth::Type, AccountManagerAuth::Required), Q_ARG(AccountManagerAuth::Type, authType),
Q_ARG(QNetworkAccessManager::Operation, operation), Q_ARG(QNetworkAccessManager::Operation, operation),
Q_ARG(const JSONCallbackParameters&, callbackParams), Q_ARG(const JSONCallbackParameters&, callbackParams),
Q_ARG(const QByteArray&, dataByteArray), Q_ARG(const QByteArray&, dataByteArray),
Q_ARG(QHttpMultiPart*, dataMultiPart), Q_ARG(QHttpMultiPart*, dataMultiPart),
Q_ARG(QVariantMap, propertyMap)); Q_ARG(QVariantMap, propertyMap));
return;
} }
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();

View file

@ -423,12 +423,12 @@ void Resource::handleReplyFinished() {
auto result = _request->getResult(); auto result = _request->getResult();
if (result == ResourceRequest::Success) { if (result == ResourceRequest::Success) {
_data = _request->getData();
auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString()); auto extraInfo = _url == _activeUrl ? "" : QString(", %1").arg(_activeUrl.toDisplayString());
qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo); qCDebug(networking).noquote() << QString("Request finished for %1%2").arg(_url.toDisplayString(), extraInfo);
emit loaded(_data); auto data = _request->getData();
downloadFinished(_data); emit loaded(data);
downloadFinished(data);
} else { } else {
switch (result) { switch (result) {
case ResourceRequest::Result::Timeout: { case ResourceRequest::Result::Timeout: {

View file

@ -194,12 +194,11 @@ public:
Q_INVOKABLE void allReferencesCleared(); Q_INVOKABLE void allReferencesCleared();
const QUrl& getURL() const { return _url; } const QUrl& getURL() const { return _url; }
const QByteArray& getData() const { return _data; }
signals: signals:
/// Fired when the resource has been downloaded. /// Fired when the resource has been downloaded.
/// This can be used instead of downloadFinished to access data before it is processed. /// This can be used instead of downloadFinished to access data before it is processed.
void loaded(const QByteArray& request); void loaded(const QByteArray request);
/// Fired when the resource has finished loading. /// Fired when the resource has finished loading.
void finished(bool success); void finished(bool success);
@ -235,7 +234,6 @@ protected:
QHash<QPointer<QObject>, float> _loadPriorities; QHash<QPointer<QObject>, float> _loadPriorities;
QWeakPointer<Resource> _self; QWeakPointer<Resource> _self;
QPointer<ResourceCache> _cache; QPointer<ResourceCache> _cache;
QByteArray _data;
private slots: private slots:
void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal); void handleDownloadProgress(uint64_t bytesReceived, uint64_t bytesTotal);

View file

@ -58,8 +58,6 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
// if no callbacks specified, call our owns // if no callbacks specified, call our owns
if (params.isEmpty()) { if (params.isEmpty()) {
params.jsonCallbackReceiver = this;
params.jsonCallbackMethod = "requestFinished";
params.errorCallbackReceiver = this; params.errorCallbackReceiver = this;
params.errorCallbackMethod = "requestError"; params.errorCallbackMethod = "requestError";
} }
@ -70,10 +68,6 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
params, NULL, multipart); params, NULL, multipart);
} }
void UserActivityLogger::requestFinished(QNetworkReply& requestReply) {
// qCDebug(networking) << object;
}
void UserActivityLogger::requestError(QNetworkReply& errorReply) { void UserActivityLogger::requestError(QNetworkReply& errorReply) {
qCDebug(networking) << errorReply.error() << "-" << errorReply.errorString(); qCDebug(networking) << errorReply.error() << "-" << errorReply.errorString();
} }

View file

@ -39,7 +39,6 @@ public slots:
void wentTo(QString destinationType, QString destinationName); void wentTo(QString destinationType, QString destinationName);
private slots: private slots:
void requestFinished(QNetworkReply& requestReply);
void requestError(QNetworkReply& errorReply); void requestError(QNetworkReply& errorReply);
private: private:

View file

@ -17,6 +17,7 @@
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtCore/QJsonObject>
#include <QtCore/QThread> #include <QtCore/QThread>
#include <LogHandler.h> #include <LogHandler.h>
@ -27,6 +28,7 @@
#include "ControlPacket.h" #include "ControlPacket.h"
#include "Packet.h" #include "Packet.h"
#include "PacketList.h" #include "PacketList.h"
#include "../UserActivityLogger.h"
#include "Socket.h" #include "Socket.h"
using namespace udt; using namespace udt;
@ -328,7 +330,39 @@ void SendQueue::run() {
nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta); nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta);
// sleep as long as we need until next packet send, if we can // sleep as long as we need until next packet send, if we can
const auto timeToSleep = duration_cast<microseconds>(nextPacketTimestamp - p_high_resolution_clock::now()); auto now = p_high_resolution_clock::now();
auto timeToSleep = duration_cast<microseconds>(nextPacketTimestamp - now);
// we're seeing SendQueues sleep for a long period of time here,
// which can lock the NodeList if it's attempting to clear connections
// for now we guard this by capping the time this thread and sleep for
const microseconds MAX_SEND_QUEUE_SLEEP_USECS { 2000000 };
if (timeToSleep > MAX_SEND_QUEUE_SLEEP_USECS) {
qWarning() << "udt::SendQueue wanted to sleep for" << timeToSleep.count() << "microseconds";
qWarning() << "Capping sleep to" << MAX_SEND_QUEUE_SLEEP_USECS.count();
qWarning() << "PSP:" << _packetSendPeriod << "NPD:" << nextPacketDelta
<< "NPT:" << nextPacketTimestamp.time_since_epoch().count()
<< "NOW:" << now.time_since_epoch().count();
// alright, we're in a weird state
// we want to know why this is happening so we can implement a better fix than this guard
// send some details up to the API (if the user allows us) that indicate how we could such a large timeToSleep
static const QString SEND_QUEUE_LONG_SLEEP_ACTION = "sendqueue-sleep";
// setup a json object with the details we want
QJsonObject longSleepObject;
longSleepObject["timeToSleep"] = qint64(timeToSleep.count());
longSleepObject["packetSendPeriod"] = _packetSendPeriod.load();
longSleepObject["nextPacketDelta"] = nextPacketDelta;
longSleepObject["nextPacketTimestamp"] = qint64(nextPacketTimestamp.time_since_epoch().count());
longSleepObject["then"] = qint64(now.time_since_epoch().count());
// hopefully send this event using the user activity logger
UserActivityLogger::getInstance().logAction(SEND_QUEUE_LONG_SLEEP_ACTION, longSleepObject);
timeToSleep = MAX_SEND_QUEUE_SLEEP_USECS;
}
std::this_thread::sleep_for(timeToSleep); std::this_thread::sleep_for(timeToSleep);
} }

View file

@ -57,16 +57,18 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
} }
void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) { void PhysicalEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
EntitySimulation::removeEntityInternal(entity); if (entity->isSimulated()) {
QMutexLocker lock(&_mutex); EntitySimulation::removeEntityInternal(entity);
_entitiesToAddToPhysics.remove(entity); QMutexLocker lock(&_mutex);
_entitiesToAddToPhysics.remove(entity);
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo()); EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
if (motionState) { if (motionState) {
_outgoingChanges.remove(motionState); _outgoingChanges.remove(motionState);
_entitiesToRemoveFromPhysics.insert(entity); _entitiesToRemoveFromPhysics.insert(entity);
} else { } else {
_entitiesToDelete.insert(entity); _entitiesToDelete.insert(entity);
}
} }
} }
@ -175,7 +177,7 @@ void PhysicalEntitySimulation::getObjectsToRemoveFromPhysics(VectorOfMotionState
_entitiesToRelease.insert(entity); _entitiesToRelease.insert(entity);
} }
if (entity->isSimulated() && entity->isDead()) { if (entity->isDead()) {
_entitiesToDelete.insert(entity); _entitiesToDelete.insert(entity);
} }
} }
@ -190,7 +192,7 @@ void PhysicalEntitySimulation::deleteObjectsRemovedFromPhysics() {
entity->setPhysicsInfo(nullptr); entity->setPhysicsInfo(nullptr);
delete motionState; delete motionState;
if (entity->isSimulated() && entity->isDead()) { if (entity->isDead()) {
_entitiesToDelete.insert(entity); _entitiesToDelete.insert(entity);
} }
} }

View file

@ -14,6 +14,7 @@
#ifndef hifi_SimpleMovingAverage_h #ifndef hifi_SimpleMovingAverage_h
#define hifi_SimpleMovingAverage_h #define hifi_SimpleMovingAverage_h
#include <mutex>
#include <stdint.h> #include <stdint.h>
class SimpleMovingAverage { class SimpleMovingAverage {
@ -64,4 +65,45 @@ public:
} }
}; };
template <class T, int MAX_NUM_SAMPLES> class ThreadSafeMovingAverage {
public:
void clear() {
std::unique_lock<std::mutex> lock(_lock);
_samples = 0;
}
bool isAverageValid() const {
std::unique_lock<std::mutex> lock(_lock);
return (_samples > 0);
}
void addSample(T sample) {
std::unique_lock<std::mutex> lock(_lock);
if (_samples > 0) {
_average = (sample * WEIGHTING) + (_average * ONE_MINUS_WEIGHTING);
} else {
_average = sample;
}
_samples++;
}
T getAverage() const {
std::unique_lock<std::mutex> lock(_lock);
return _average;
}
size_t getSamples() const {
std::unique_lock<std::mutex> lock(_lock);
return _samples;
}
private:
const float WEIGHTING = 1.0f / (float)MAX_NUM_SAMPLES;
const float ONE_MINUS_WEIGHTING = 1.0f - WEIGHTING;
size_t _samples { 0 };
T _average;
mutable std::mutex _lock;
};
#endif // hifi_SimpleMovingAverage_h #endif // hifi_SimpleMovingAverage_h

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 78 KiB