Progress on threading.

This commit is contained in:
Andrzej Kapolka 2014-07-23 18:20:00 -07:00
parent 4ea8e7de5d
commit 27f88e9f80
10 changed files with 274 additions and 119 deletions

View file

@ -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),

View file

@ -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:

View file

@ -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);
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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) {

View file

@ -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.