Merge branch 'master' of github.com:highfidelity/hifi into fix-logging-crash
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 51 KiB |
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 320 KiB After Width: | Height: | Size: 110 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 271 KiB After Width: | Height: | Size: 78 KiB |