mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
Progress on threading.
This commit is contained in:
parent
4ea8e7de5d
commit
27f88e9f80
10 changed files with 274 additions and 119 deletions
|
@ -21,8 +21,6 @@
|
|||
|
||||
#include "MetavoxelServer.h"
|
||||
|
||||
const int SEND_INTERVAL = 50;
|
||||
|
||||
MetavoxelServer::MetavoxelServer(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_nextSender(0) {
|
||||
|
@ -48,8 +46,8 @@ void MetavoxelServer::run() {
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||
|
||||
connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachSession(const SharedNodePointer&)));
|
||||
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteSession(const SharedNodePointer&)));
|
||||
connect(nodeList, &NodeList::nodeAdded, this, &MetavoxelServer::maybeAttachSession);
|
||||
connect(nodeList, &NodeList::nodeKilled, this, &MetavoxelServer::maybeDeleteSession);
|
||||
|
||||
// initialize Bitstream before using it in multiple threads
|
||||
Bitstream::preThreadingInit();
|
||||
|
@ -65,7 +63,7 @@ void MetavoxelServer::run() {
|
|||
QThread* thread = new QThread(this);
|
||||
MetavoxelSender* sender = new MetavoxelSender(this);
|
||||
sender->moveToThread(thread);
|
||||
sender->connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
|
||||
connect(thread, &QThread::finished, sender, &QObject::deleteLater);
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(sender, "start");
|
||||
_senders.append(sender);
|
||||
|
@ -75,7 +73,7 @@ void MetavoxelServer::run() {
|
|||
_persister = new MetavoxelPersister(this);
|
||||
QThread* persistenceThread = new QThread(this);
|
||||
_persister->moveToThread(persistenceThread);
|
||||
_persister->connect(persistenceThread, SIGNAL(finished()), SLOT(deleteLater()));
|
||||
connect(persistenceThread, &QThread::finished, _persister, &QObject::deleteLater);
|
||||
persistenceThread->start();
|
||||
|
||||
// queue up the load
|
||||
|
@ -121,15 +119,16 @@ void MetavoxelServer::maybeAttachSession(const SharedNodePointer& node) {
|
|||
_nextSender = (_nextSender + 1) % _senders.size();
|
||||
MetavoxelSession* session = new MetavoxelSession(node, sender);
|
||||
session->moveToThread(sender->thread());
|
||||
QMetaObject::invokeMethod(sender, "addSession", Q_ARG(QObject*, session));
|
||||
node->setLinkedData(session);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelServer::maybeDeleteSession(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
// we assume the node is already locked
|
||||
MetavoxelSession* session = static_cast<MetavoxelSession*>(node->getLinkedData());
|
||||
if (session) {
|
||||
if (session) {
|
||||
node->setLinkedData(NULL);
|
||||
session->deleteLater();
|
||||
}
|
||||
|
@ -141,26 +140,27 @@ MetavoxelSender::MetavoxelSender(MetavoxelServer* server) :
|
|||
_sendTimer(this) {
|
||||
|
||||
_sendTimer.setSingleShot(true);
|
||||
connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas()));
|
||||
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelSender::sendDeltas);
|
||||
|
||||
connect(_server, &MetavoxelServer::dataChanged, this, &MetavoxelSender::setData);
|
||||
}
|
||||
|
||||
const int SEND_INTERVAL = 50;
|
||||
|
||||
void MetavoxelSender::start() {
|
||||
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
||||
_sendTimer.start(SEND_INTERVAL);
|
||||
}
|
||||
|
||||
void MetavoxelSender::addSession(QObject* session) {
|
||||
_sessions.insert(static_cast<MetavoxelSession*>(session));
|
||||
connect(session, &QObject::destroyed, this, &MetavoxelSender::removeSession);
|
||||
}
|
||||
|
||||
void MetavoxelSender::sendDeltas() {
|
||||
// send deltas for all sessions associated with our thread
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::Agent) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSession* session = static_cast<MetavoxelSession*>(node->getLinkedData());
|
||||
if (session && session->thread() == QThread::currentThread()) {
|
||||
session->update();
|
||||
}
|
||||
}
|
||||
foreach (MetavoxelSession* session, _sessions) {
|
||||
session->update();
|
||||
}
|
||||
|
||||
// restart the send timer
|
||||
|
@ -171,6 +171,10 @@ void MetavoxelSender::sendDeltas() {
|
|||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
|
||||
}
|
||||
|
||||
void MetavoxelSender::removeSession(QObject* session) {
|
||||
_sessions.remove(static_cast<MetavoxelSession*>(session));
|
||||
}
|
||||
|
||||
MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender) :
|
||||
Endpoint(node, new PacketRecord(), NULL),
|
||||
_sender(sender),
|
||||
|
|
|
@ -77,14 +77,18 @@ public:
|
|||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
Q_INVOKABLE void addSession(QObject* session);
|
||||
|
||||
private slots:
|
||||
|
||||
void setData(const MetavoxelData& data) { _data = data; }
|
||||
void sendDeltas();
|
||||
void removeSession(QObject* session);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelServer* _server;
|
||||
QSet<MetavoxelSession*> _sessions;
|
||||
|
||||
QTimer _sendTimer;
|
||||
qint64 _lastSend;
|
||||
|
@ -99,7 +103,7 @@ class MetavoxelSession : public Endpoint {
|
|||
public:
|
||||
|
||||
MetavoxelSession(const SharedNodePointer& node, MetavoxelSender* sender);
|
||||
|
||||
|
||||
virtual void update();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
//
|
||||
|
||||
#include <QMutexLocker>
|
||||
#include <QReadLocker>
|
||||
#include <QWriteLocker>
|
||||
#include <QtDebug>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
@ -45,11 +47,9 @@ void MetavoxelSystem::init() {
|
|||
_pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new PointBufferAttribute());
|
||||
}
|
||||
|
||||
MetavoxelLOD MetavoxelSystem::getLOD() const {
|
||||
// the LOD threshold is temporarily tied to the avatar LOD parameter
|
||||
const float BASE_LOD_THRESHOLD = 0.01f;
|
||||
return MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(),
|
||||
BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier());
|
||||
MetavoxelLOD MetavoxelSystem::getLOD() {
|
||||
QReadLocker locker(&_lodLock);
|
||||
return _lod;
|
||||
}
|
||||
|
||||
class SpannerSimulateVisitor : public SpannerVisitor {
|
||||
|
@ -77,9 +77,15 @@ bool SpannerSimulateVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimu
|
|||
}
|
||||
|
||||
void MetavoxelSystem::simulate(float deltaTime) {
|
||||
// update the clients
|
||||
update();
|
||||
|
||||
// update the lod
|
||||
{
|
||||
// the LOD threshold is temporarily tied to the avatar LOD parameter
|
||||
QWriteLocker locker(&_lodLock);
|
||||
const float BASE_LOD_THRESHOLD = 0.01f;
|
||||
_lod = MetavoxelLOD(Application::getInstance()->getCamera()->getPosition(),
|
||||
BASE_LOD_THRESHOLD * Menu::getInstance()->getAvatarLODDistanceMultiplier());
|
||||
}
|
||||
|
||||
SpannerSimulateVisitor spannerSimulateVisitor(deltaTime);
|
||||
guide(spannerSimulateVisitor);
|
||||
}
|
||||
|
@ -183,16 +189,20 @@ void MetavoxelSystem::render() {
|
|||
guide(spannerRenderVisitor);
|
||||
}
|
||||
|
||||
void MetavoxelSystem::setClientPoints(const SharedNodePointer& node, const BufferPointVector& points) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelSystemClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->setPoints(points);
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelClient* MetavoxelSystem::createClient(const SharedNodePointer& node) {
|
||||
return new MetavoxelSystemClient(node, this);
|
||||
return new MetavoxelSystemClient(node, _updater);
|
||||
}
|
||||
|
||||
void MetavoxelSystem::updateClient(MetavoxelClient* client) {
|
||||
MetavoxelClientManager::updateClient(client);
|
||||
}
|
||||
|
||||
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system) :
|
||||
MetavoxelClient(node, system),
|
||||
MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
|
||||
MetavoxelClient(node, updater),
|
||||
_pointCount(0) {
|
||||
|
||||
_buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
||||
|
@ -385,11 +395,14 @@ void PointBufferBuilder::run() {
|
|||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
PointCollector collector(_lod);
|
||||
_data.guide(collector);
|
||||
QMetaObject::invokeMethod(node->getLinkedData(), "setPoints", Q_ARG(const BufferPointVector&, collector.points));
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels(), "setClientPoints",
|
||||
Q_ARG(const SharedNodePointer&, node), Q_ARG(const BufferPointVector&, collector.points));
|
||||
qDebug() << "collect" << (QDateTime::currentMSecsSinceEpoch() - now);
|
||||
}
|
||||
|
||||
void MetavoxelSystemClient::dataChanged(const MetavoxelData& oldData) {
|
||||
MetavoxelClient::dataChanged(oldData);
|
||||
|
||||
/* BufferBuilder builder(_remoteDataLOD);
|
||||
const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute();
|
||||
MetavoxelNode* oldRoot = oldData.getRoot(pointBufferAttribute);
|
||||
|
@ -500,7 +513,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum
|
|||
return;
|
||||
}
|
||||
// slight performance optimization: don't render if clip bounds are entirely within sphere
|
||||
Sphere* sphere = static_cast<Sphere*>(parent());
|
||||
Sphere* sphere = static_cast<Sphere*>(_spanner);
|
||||
Box clipBox(clipMinimum, clipMinimum + glm::vec3(clipSize, clipSize, clipSize));
|
||||
for (int i = 0; i < Box::VERTEX_COUNT; i++) {
|
||||
const float CLIP_PROPORTION = 0.95f;
|
||||
|
@ -512,7 +525,7 @@ void SphereRenderer::render(float alpha, Mode mode, const glm::vec3& clipMinimum
|
|||
}
|
||||
|
||||
void SphereRenderer::renderUnclipped(float alpha, Mode mode) {
|
||||
Sphere* sphere = static_cast<Sphere*>(parent());
|
||||
Sphere* sphere = static_cast<Sphere*>(_spanner);
|
||||
const QColor& color = sphere->getColor();
|
||||
glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF() * alpha);
|
||||
|
||||
|
@ -533,6 +546,8 @@ StaticModelRenderer::StaticModelRenderer() :
|
|||
}
|
||||
|
||||
void StaticModelRenderer::init(Spanner* spanner) {
|
||||
SpannerRenderer::init(spanner);
|
||||
|
||||
_model->init();
|
||||
|
||||
StaticModel* staticModel = static_cast<StaticModel*>(spanner);
|
||||
|
@ -554,7 +569,7 @@ void StaticModelRenderer::simulate(float deltaTime) {
|
|||
const Extents& extents = _model->getGeometry()->getFBXGeometry().meshExtents;
|
||||
bounds = Box(extents.minimum, extents.maximum);
|
||||
}
|
||||
static_cast<StaticModel*>(parent())->setBounds(glm::translate(_model->getTranslation()) *
|
||||
static_cast<StaticModel*>(_spanner)->setBounds(glm::translate(_model->getTranslation()) *
|
||||
glm::mat4_cast(_model->getRotation()) * glm::scale(_model->getScale()) * bounds);
|
||||
_model->simulate(deltaTime);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QList>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QReadWriteLock>
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -22,8 +23,12 @@
|
|||
|
||||
#include "renderer/ProgramObject.h"
|
||||
|
||||
class BufferPoint;
|
||||
class Model;
|
||||
|
||||
typedef QVector<BufferPoint> BufferPointVector;
|
||||
typedef QPair<BufferPointVector, BufferPointVector> BufferPointVectorPair;
|
||||
|
||||
/// Renders a metavoxel tree.
|
||||
class MetavoxelSystem : public MetavoxelClientManager {
|
||||
Q_OBJECT
|
||||
|
@ -34,15 +39,16 @@ public:
|
|||
|
||||
virtual void init();
|
||||
|
||||
virtual MetavoxelLOD getLOD() const;
|
||||
virtual MetavoxelLOD getLOD();
|
||||
|
||||
void simulate(float deltaTime);
|
||||
void render();
|
||||
|
||||
Q_INVOKABLE void setClientPoints(const SharedNodePointer& node, const BufferPointVector& points);
|
||||
|
||||
protected:
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
virtual void updateClient(MetavoxelClient* client);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -50,6 +56,9 @@ private:
|
|||
static int _pointScaleLocation;
|
||||
|
||||
AttributePointer _pointBufferAttribute;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
QReadWriteLock _lodLock;
|
||||
};
|
||||
|
||||
/// Describes contents of a point in a point buffer.
|
||||
|
@ -60,9 +69,6 @@ public:
|
|||
quint8 normal[3];
|
||||
};
|
||||
|
||||
typedef QVector<BufferPoint> BufferPointVector;
|
||||
typedef QPair<BufferPointVector, BufferPointVector> BufferPointVectorPair;
|
||||
|
||||
Q_DECLARE_METATYPE(BufferPointVector)
|
||||
|
||||
/// A client session associated with a single server.
|
||||
|
@ -71,11 +77,11 @@ class MetavoxelSystemClient : public MetavoxelClient {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelSystem* system);
|
||||
MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
|
||||
|
||||
void render();
|
||||
|
||||
Q_INVOKABLE void setPoints(const BufferPointVector& points);
|
||||
void setPoints(const BufferPointVector& points);
|
||||
|
||||
virtual int parseData(const QByteArray& packet);
|
||||
|
||||
|
|
|
@ -48,7 +48,13 @@ Stats::Stats():
|
|||
_pingStatsWidth(STATS_PING_MIN_WIDTH),
|
||||
_geoStatsWidth(STATS_GEO_MIN_WIDTH),
|
||||
_voxelStatsWidth(STATS_VOXEL_MIN_WIDTH),
|
||||
_lastHorizontalOffset(0)
|
||||
_lastHorizontalOffset(0),
|
||||
_metavoxelInternal(0),
|
||||
_metavoxelLeaves(0),
|
||||
_metavoxelSendProgress(0),
|
||||
_metavoxelSendTotal(0),
|
||||
_metavoxelReceiveProgress(0),
|
||||
_metavoxelReceiveTotal(0)
|
||||
{
|
||||
QGLWidget* glWidget = Application::getInstance()->getGLWidget();
|
||||
resetWidth(glWidget->width(), 0);
|
||||
|
@ -487,36 +493,26 @@ void Stats::display(
|
|||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, downloads.str().c_str(), color);
|
||||
|
||||
int internal = 0, leaves = 0;
|
||||
int sendProgress = 0, sendTotal = 0;
|
||||
int receiveProgress = 0, receiveTotal = 0;
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelSystemClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->getData().countNodes(internal, leaves, Application::getInstance()->getMetavoxels()->getLOD());
|
||||
client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal);
|
||||
}
|
||||
}
|
||||
}
|
||||
QMetaObject::invokeMethod(Application::getInstance()->getMetavoxels()->getUpdater(), "getStats",
|
||||
Q_ARG(QObject*, this), Q_ARG(const QByteArray&, "setMetavoxelStats"));
|
||||
|
||||
stringstream nodes;
|
||||
nodes << "Metavoxels: " << (internal + leaves);
|
||||
nodes << "Metavoxels: " << (_metavoxelInternal + _metavoxelLeaves);
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodes.str().c_str(), color);
|
||||
|
||||
stringstream nodeTypes;
|
||||
nodeTypes << "Internal: " << internal << " Leaves: " << leaves;
|
||||
nodeTypes << "Internal: " << _metavoxelInternal << " Leaves: " << _metavoxelLeaves;
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, nodeTypes.str().c_str(), color);
|
||||
|
||||
if (sendTotal > 0 || receiveTotal > 0) {
|
||||
if (_metavoxelSendTotal > 0 || _metavoxelReceiveTotal > 0) {
|
||||
stringstream reliableStats;
|
||||
if (sendTotal > 0) {
|
||||
reliableStats << "Upload: " << (sendProgress * 100 / sendTotal) << "% ";
|
||||
if (_metavoxelSendTotal > 0) {
|
||||
reliableStats << "Upload: " << (_metavoxelSendProgress * 100 / _metavoxelSendTotal) << "% ";
|
||||
}
|
||||
if (receiveTotal > 0) {
|
||||
reliableStats << "Download: " << (receiveProgress * 100 / receiveTotal) << "%";
|
||||
if (_metavoxelReceiveTotal > 0) {
|
||||
reliableStats << "Download: " << (_metavoxelReceiveProgress * 100 / _metavoxelReceiveTotal) << "%";
|
||||
}
|
||||
verticalOffset += STATS_PELS_PER_LINE;
|
||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, reliableStats.str().c_str(), color);
|
||||
|
@ -849,3 +845,13 @@ void Stats::display(
|
|||
|
||||
|
||||
}
|
||||
|
||||
void Stats::setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||
int sendTotal, int receiveProgress, int receiveTotal) {
|
||||
_metavoxelInternal = internal;
|
||||
_metavoxelLeaves = leaves;
|
||||
_metavoxelSendProgress = sendProgress;
|
||||
_metavoxelSendTotal = sendTotal;
|
||||
_metavoxelReceiveProgress = receiveProgress;
|
||||
_metavoxelReceiveTotal = receiveTotal;
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ public:
|
|||
void resetWidth(int width, int horizontalOffset);
|
||||
void display(const float* color, int horizontalOffset, float fps, int packetsPerSecond, int bytesPerSecond, int voxelPacketsToProcess);
|
||||
bool includeTimingRecord(const QString& name);
|
||||
|
||||
Q_INVOKABLE void setMetavoxelStats(int internal, int leaves, int sendProgress,
|
||||
int sendTotal, int receiveProgress, int receiveTotal);
|
||||
|
||||
private:
|
||||
static Stats* _sharedInstance;
|
||||
|
||||
|
@ -45,6 +49,13 @@ private:
|
|||
int _voxelStatsWidth;
|
||||
|
||||
int _lastHorizontalOffset;
|
||||
|
||||
int _metavoxelInternal;
|
||||
int _metavoxelLeaves;
|
||||
int _metavoxelSendProgress;
|
||||
int _metavoxelSendTotal;
|
||||
int _metavoxelReceiveProgress;
|
||||
int _metavoxelReceiveTotal;
|
||||
};
|
||||
|
||||
#endif // hifi_Stats_h
|
||||
|
|
|
@ -9,26 +9,31 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QReadLocker>
|
||||
#include <QThread>
|
||||
#include <QWriteLocker>
|
||||
|
||||
#include "MetavoxelClientManager.h"
|
||||
#include "MetavoxelMessages.h"
|
||||
|
||||
void MetavoxelClientManager::init() {
|
||||
connect(NodeList::getInstance(), SIGNAL(nodeAdded(SharedNodePointer)), SLOT(maybeAttachClient(const SharedNodePointer&)));
|
||||
connect(NodeList::getInstance(), SIGNAL(nodeKilled(SharedNodePointer)), SLOT(maybeDeleteClient(const SharedNodePointer&)));
|
||||
MetavoxelClientManager::MetavoxelClientManager() :
|
||||
_updater(new MetavoxelUpdater(this)) {
|
||||
QThread* thread = new QThread(this);
|
||||
_updater->moveToThread(thread);
|
||||
connect(thread, &QThread::finished, _updater, &QObject::deleteLater);
|
||||
thread->start();
|
||||
QMetaObject::invokeMethod(_updater, "start");
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::update() {
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
updateClient(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
MetavoxelClientManager::~MetavoxelClientManager() {
|
||||
_updater->thread()->quit();
|
||||
_updater->thread()->wait();
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::init() {
|
||||
connect(NodeList::getInstance(), &NodeList::nodeAdded, this, &MetavoxelClientManager::maybeAttachClient);
|
||||
connect(NodeList::getInstance(), &NodeList::nodeKilled, this, &MetavoxelClientManager::maybeDeleteClient);
|
||||
}
|
||||
|
||||
SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(const glm::vec3& origin,
|
||||
|
@ -41,7 +46,7 @@ SharedObjectPointer MetavoxelClientManager::findFirstRaySpannerIntersection(cons
|
|||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
float clientDistance;
|
||||
SharedObjectPointer clientSpanner = client->getData().findFirstRaySpannerIntersection(
|
||||
SharedObjectPointer clientSpanner = client->getDataCopy().findFirstRaySpannerIntersection(
|
||||
origin, direction, attribute, clientDistance);
|
||||
if (clientSpanner && clientDistance < closestDistance) {
|
||||
closestSpanner = clientSpanner;
|
||||
|
@ -70,35 +75,26 @@ void MetavoxelClientManager::setSpanner(const SharedObjectPointer& object, bool
|
|||
}
|
||||
|
||||
void MetavoxelClientManager::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
|
||||
return;
|
||||
}
|
||||
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->applyEdit(edit, reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
QMetaObject::invokeMethod(_updater, "applyEdit", Q_ARG(const MetavoxelEditMessage&, edit), Q_ARG(bool, reliable));
|
||||
}
|
||||
|
||||
MetavoxelLOD MetavoxelClientManager::getLOD() const {
|
||||
MetavoxelLOD MetavoxelClientManager::getLOD() {
|
||||
return MetavoxelLOD();
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::maybeAttachClient(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
node->setLinkedData(createClient(node));
|
||||
MetavoxelClient* client = createClient(node);
|
||||
client->moveToThread(_updater->thread());
|
||||
QMetaObject::invokeMethod(_updater, "addClient", Q_ARG(QObject*, client));
|
||||
node->setLinkedData(client);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) {
|
||||
if (node->getType() == NodeType::MetavoxelServer) {
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
// we assume the node is already locked
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
node->setLinkedData(NULL);
|
||||
|
@ -108,11 +104,7 @@ void MetavoxelClientManager::maybeDeleteClient(const SharedNodePointer& node) {
|
|||
}
|
||||
|
||||
MetavoxelClient* MetavoxelClientManager::createClient(const SharedNodePointer& node) {
|
||||
return new MetavoxelClient(node, this);
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::updateClient(MetavoxelClient* client) {
|
||||
client->update();
|
||||
return new MetavoxelClient(node, _updater);
|
||||
}
|
||||
|
||||
void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) {
|
||||
|
@ -121,15 +113,75 @@ void MetavoxelClientManager::guide(MetavoxelVisitor& visitor) {
|
|||
QMutexLocker locker(&node->getMutex());
|
||||
MetavoxelClient* client = static_cast<MetavoxelClient*>(node->getLinkedData());
|
||||
if (client) {
|
||||
client->guide(visitor);
|
||||
client->getDataCopy().guide(visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) :
|
||||
MetavoxelUpdater::MetavoxelUpdater(MetavoxelClientManager* clientManager) :
|
||||
_clientManager(clientManager),
|
||||
_sendTimer(this) {
|
||||
|
||||
_sendTimer.setSingleShot(true);
|
||||
connect(&_sendTimer, &QTimer::timeout, this, &MetavoxelUpdater::sendUpdates);
|
||||
}
|
||||
|
||||
const int SEND_INTERVAL = 33;
|
||||
|
||||
void MetavoxelUpdater::start() {
|
||||
_lastSend = QDateTime::currentMSecsSinceEpoch();
|
||||
_sendTimer.start(SEND_INTERVAL);
|
||||
}
|
||||
|
||||
void MetavoxelUpdater::addClient(QObject* client) {
|
||||
_clients.insert(static_cast<MetavoxelClient*>(client));
|
||||
connect(client, &QObject::destroyed, this, &MetavoxelUpdater::removeClient);
|
||||
}
|
||||
|
||||
void MetavoxelUpdater::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
// apply to all clients
|
||||
foreach (MetavoxelClient* client, _clients) {
|
||||
client->applyEdit(edit, reliable);
|
||||
}
|
||||
}
|
||||
|
||||
void MetavoxelUpdater::getStats(QObject* receiver, const QByteArray& method) {
|
||||
int internal = 0, leaves = 0;
|
||||
int sendProgress = 0, sendTotal = 0;
|
||||
int receiveProgress = 0, receiveTotal = 0;
|
||||
foreach (MetavoxelClient* client, _clients) {
|
||||
client->getData().countNodes(internal, leaves, _lod);
|
||||
client->getSequencer().addReliableChannelStats(sendProgress, sendTotal, receiveProgress, receiveTotal);
|
||||
}
|
||||
QMetaObject::invokeMethod(receiver, method.constData(), Q_ARG(int, internal), Q_ARG(int, leaves), Q_ARG(int, sendProgress),
|
||||
Q_ARG(int, sendTotal), Q_ARG(int, receiveProgress), Q_ARG(int, receiveTotal));
|
||||
}
|
||||
|
||||
void MetavoxelUpdater::sendUpdates() {
|
||||
// get the latest LOD from the client manager
|
||||
_lod = _clientManager->getLOD();
|
||||
|
||||
// send updates for all clients
|
||||
foreach (MetavoxelClient* client, _clients) {
|
||||
client->update();
|
||||
}
|
||||
|
||||
// restart the send timer
|
||||
qint64 now = QDateTime::currentMSecsSinceEpoch();
|
||||
int elapsed = now - _lastSend;
|
||||
_lastSend = now;
|
||||
|
||||
_sendTimer.start(qMax(0, 2 * SEND_INTERVAL - qMax(elapsed, SEND_INTERVAL)));
|
||||
}
|
||||
|
||||
void MetavoxelUpdater::removeClient(QObject* client) {
|
||||
_clients.remove(static_cast<MetavoxelClient*>(client));
|
||||
}
|
||||
|
||||
MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater) :
|
||||
Endpoint(node, new PacketRecord(), new PacketRecord()),
|
||||
_manager(manager),
|
||||
_updater(updater),
|
||||
_reliableDeltaChannel(NULL),
|
||||
_reliableDeltaID(0) {
|
||||
|
||||
|
@ -137,9 +189,9 @@ MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientM
|
|||
SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&)));
|
||||
}
|
||||
|
||||
void MetavoxelClient::guide(MetavoxelVisitor& visitor) {
|
||||
visitor.setLOD(_manager->getLOD());
|
||||
_data.guide(visitor);
|
||||
MetavoxelData MetavoxelClient::getDataCopy() {
|
||||
QReadLocker locker(&_dataCopyLock);
|
||||
return _dataCopy;
|
||||
}
|
||||
|
||||
void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable) {
|
||||
|
@ -160,11 +212,13 @@ void MetavoxelClient::applyEdit(const MetavoxelEditMessage& edit, bool reliable)
|
|||
}
|
||||
|
||||
void MetavoxelClient::dataChanged(const MetavoxelData& oldData) {
|
||||
// nothing by default
|
||||
// make thread-safe copy
|
||||
QWriteLocker locker(&_dataCopyLock);
|
||||
_dataCopy = _data;
|
||||
}
|
||||
|
||||
void MetavoxelClient::writeUpdateMessage(Bitstream& out) {
|
||||
ClientStateMessage state = { _manager->getLOD() };
|
||||
ClientStateMessage state = { _updater->getLOD() };
|
||||
out << QVariant::fromValue(state);
|
||||
}
|
||||
|
||||
|
@ -212,7 +266,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) {
|
|||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateSendRecord() const {
|
||||
return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _manager->getLOD());
|
||||
return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _updater->getLOD());
|
||||
}
|
||||
|
||||
PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const {
|
||||
|
|
|
@ -12,10 +12,14 @@
|
|||
#ifndef hifi_MetavoxelClientManager_h
|
||||
#define hifi_MetavoxelClientManager_h
|
||||
|
||||
#include <QReadWriteLock>
|
||||
#include <QTimer>
|
||||
|
||||
#include "Endpoint.h"
|
||||
|
||||
class MetavoxelClient;
|
||||
class MetavoxelEditMessage;
|
||||
class MetavoxelUpdater;
|
||||
|
||||
/// Manages the set of connected metavoxel clients.
|
||||
class MetavoxelClientManager : public QObject {
|
||||
|
@ -23,8 +27,12 @@ class MetavoxelClientManager : public QObject {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelClientManager();
|
||||
virtual ~MetavoxelClientManager();
|
||||
|
||||
virtual void init();
|
||||
void update();
|
||||
|
||||
MetavoxelUpdater* getUpdater() const { return _updater; }
|
||||
|
||||
SharedObjectPointer findFirstRaySpannerIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const AttributePointer& attribute, float& distance);
|
||||
|
@ -35,7 +43,8 @@ public:
|
|||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
|
||||
virtual MetavoxelLOD getLOD() const;
|
||||
/// Returns the current LOD. This must be thread-safe, as it will be called from the updater thread.
|
||||
virtual MetavoxelLOD getLOD();
|
||||
|
||||
private slots:
|
||||
|
||||
|
@ -45,9 +54,46 @@ private slots:
|
|||
protected:
|
||||
|
||||
virtual MetavoxelClient* createClient(const SharedNodePointer& node);
|
||||
virtual void updateClient(MetavoxelClient* client);
|
||||
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
MetavoxelUpdater* _updater;
|
||||
};
|
||||
|
||||
/// Handles updates in a dedicated thread.
|
||||
class MetavoxelUpdater : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
MetavoxelUpdater(MetavoxelClientManager* clientManager);
|
||||
|
||||
const MetavoxelLOD& getLOD() const { return _lod; }
|
||||
|
||||
Q_INVOKABLE void start();
|
||||
|
||||
Q_INVOKABLE void addClient(QObject* client);
|
||||
|
||||
Q_INVOKABLE void applyEdit(const MetavoxelEditMessage& edit, bool reliable);
|
||||
|
||||
/// Requests a set of statistics. The receiving method should take six integer arguments: internal node count, leaf count,
|
||||
/// send progress, send total, receive progress, receive total.
|
||||
Q_INVOKABLE void getStats(QObject* receiver, const QByteArray& method);
|
||||
|
||||
private slots:
|
||||
|
||||
void sendUpdates();
|
||||
void removeClient(QObject* client);
|
||||
|
||||
private:
|
||||
|
||||
MetavoxelClientManager* _clientManager;
|
||||
QSet<MetavoxelClient*> _clients;
|
||||
|
||||
QTimer _sendTimer;
|
||||
qint64 _lastSend;
|
||||
|
||||
MetavoxelLOD _lod;
|
||||
};
|
||||
|
||||
/// Base class for metavoxel clients.
|
||||
|
@ -56,12 +102,14 @@ class MetavoxelClient : public Endpoint {
|
|||
|
||||
public:
|
||||
|
||||
MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager);
|
||||
MetavoxelClient(const SharedNodePointer& node, MetavoxelUpdater* updater);
|
||||
|
||||
MetavoxelData& getData() { return _data; }
|
||||
/// Returns a reference to the most recent data. This function is *not* thread-safe.
|
||||
const MetavoxelData& getData() const { return _data; }
|
||||
|
||||
/// Returns a copy of the most recent data. This function *is* thread-safe.
|
||||
MetavoxelData getDataCopy();
|
||||
|
||||
void guide(MetavoxelVisitor& visitor);
|
||||
|
||||
void applyEdit(const MetavoxelEditMessage& edit, bool reliable = false);
|
||||
|
||||
protected:
|
||||
|
@ -74,7 +122,7 @@ protected:
|
|||
virtual PacketRecord* maybeCreateSendRecord() const;
|
||||
virtual PacketRecord* maybeCreateReceiveRecord() const;
|
||||
|
||||
MetavoxelClientManager* _manager;
|
||||
MetavoxelUpdater* _updater;
|
||||
MetavoxelData _data;
|
||||
MetavoxelData _remoteData;
|
||||
MetavoxelLOD _remoteDataLOD;
|
||||
|
@ -82,6 +130,9 @@ protected:
|
|||
ReliableChannel* _reliableDeltaChannel;
|
||||
MetavoxelLOD _reliableDeltaLOD;
|
||||
int _reliableDeltaID;
|
||||
|
||||
MetavoxelData _dataCopy;
|
||||
QReadWriteLock _dataCopyLock;
|
||||
};
|
||||
|
||||
#endif // hifi_MetavoxelClientManager_h
|
||||
|
|
|
@ -1899,7 +1899,7 @@ SpannerRenderer* Spanner::getRenderer() {
|
|||
metaObject = &SpannerRenderer::staticMetaObject;
|
||||
}
|
||||
_renderer = static_cast<SpannerRenderer*>(metaObject->newInstance());
|
||||
_renderer->setParent(this);
|
||||
connect(this, &QObject::destroyed, _renderer, &QObject::deleteLater);
|
||||
_renderer->init(this);
|
||||
}
|
||||
return _renderer;
|
||||
|
@ -1920,7 +1920,7 @@ SpannerRenderer::SpannerRenderer() {
|
|||
}
|
||||
|
||||
void SpannerRenderer::init(Spanner* spanner) {
|
||||
// nothing by default
|
||||
_spanner = spanner;
|
||||
}
|
||||
|
||||
void SpannerRenderer::simulate(float deltaTime) {
|
||||
|
|
|
@ -599,6 +599,10 @@ public:
|
|||
virtual void render(float alpha, Mode mode, const glm::vec3& clipMinimum, float clipSize);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const glm::vec3& clipMinimum, float clipSize, float& distance) const;
|
||||
|
||||
protected:
|
||||
|
||||
Spanner* _spanner;
|
||||
};
|
||||
|
||||
/// An object with a 3D transform.
|
||||
|
|
Loading…
Reference in a new issue