From cda88bf4afcc4dc2b21fc89b2c672a50f7b30e57 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 12:06:32 -0700 Subject: [PATCH 01/15] Add backgroundColor to TextOverlay --- interface/src/ui/overlays/TextOverlay.cpp | 14 +++++++++++++- interface/src/ui/overlays/TextOverlay.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 797d0be1a2..5fc98810be 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -33,7 +33,7 @@ void TextOverlay::render() { } const float MAX_COLOR = 255; - glColor4f(0 / MAX_COLOR, 0 / MAX_COLOR, 0 / MAX_COLOR, _alpha); + glColor4f(_backgroundColor.red / MAX_COLOR, _backgroundColor.green / MAX_COLOR, _backgroundColor.blue / MAX_COLOR, _alpha); glBegin(GL_QUADS); glVertex2f(_bounds.left(), _bounds.top()); @@ -82,6 +82,18 @@ void TextOverlay::setProperties(const QScriptValue& properties) { setText(text.toVariant().toString()); } + QScriptValue backgroundColor = properties.property("backgroundColor"); + if (backgroundColor.isValid()) { + QScriptValue red = backgroundColor.property("red"); + QScriptValue green = backgroundColor.property("green"); + QScriptValue blue = backgroundColor.property("blue"); + if (red.isValid() && green.isValid() && blue.isValid()) { + _backgroundColor.red = red.toVariant().toInt(); + _backgroundColor.green = green.toVariant().toInt(); + _backgroundColor.blue = blue.toVariant().toInt(); + } + } + if (properties.property("leftMargin").isValid()) { setLeftMargin(properties.property("leftMargin").toVariant().toInt()); } diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 78a037762e..6de415dcc7 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -55,6 +55,7 @@ public: private: QString _text; + xColor _backgroundColor; int _leftMargin; int _topMargin; int _fontSize; From 9ae65e443999d7fa9e1bb9848b413fd966c32f37 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 12:06:50 -0700 Subject: [PATCH 02/15] Update locationsMenu.js to use backgroundColor --- examples/locationsMenu.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/locationsMenu.js b/examples/locationsMenu.js index 6f4a28fe38..24b0dabf46 100644 --- a/examples/locationsMenu.js +++ b/examples/locationsMenu.js @@ -57,7 +57,7 @@ var LocationMenu = function(opts) { y: 0, width: menuWidth + 10, height: (menuHeight * (pageSize + 1)) + 10, - color: { red: 0, green: 0, blue: 0}, + backgroundColor: { red: 0, green: 0, blue: 0}, topMargin: 4, leftMargin: 4, text: "", @@ -71,7 +71,7 @@ var LocationMenu = function(opts) { y: 0, width: menuWidth, height: menuHeight, - color: inactiveColor, + backgroundColor: inactiveColor, topMargin: margin, leftMargin: margin, text: (i == 0) ? "Loading..." : "", @@ -85,7 +85,7 @@ var LocationMenu = function(opts) { y: 0, width: menuWidth / 2, height: menuHeight, - color: disabledColor, + backgroundColor: disabledColor, topMargin: margin, leftMargin: margin, text: "Previous", @@ -97,7 +97,7 @@ var LocationMenu = function(opts) { y: 0, width: menuWidth / 2, height: menuHeight, - color: disabledColor, + backgroundColor: disabledColor, topMargin: margin, leftMargin: margin, text: "Next", @@ -175,10 +175,10 @@ var LocationMenu = function(opts) { if (start + i < this.locations.length) { location = this.locations[start + i]; update.text = (start + i + 1) + ". " + location.username; - update.color = inactiveColor; + update.backgroundColor = inactiveColor; } else { update.text = ""; - update.color = disabledColor; + update.backgroundColor = disabledColor; } Overlays.editOverlay(this.menuItems[i].overlay, update); this.menuItems[i].location = location; @@ -187,8 +187,8 @@ var LocationMenu = function(opts) { this.previousEnabled = pageNumber > 0; this.nextEnabled = pageNumber < (this.numPages - 1); - Overlays.editOverlay(this.previousButton, { color: this.previousEnabled ? prevNextColor : disabledColor}); - Overlays.editOverlay(this.nextButton, { color: this.nextEnabled ? prevNextColor : disabledColor }); + Overlays.editOverlay(this.previousButton, { backgroundColor: this.previousEnabled ? prevNextColor : disabledColor}); + Overlays.editOverlay(this.nextButton, { backgroundColor: this.nextEnabled ? prevNextColor : disabledColor }); } this.mousePressEvent = function(event) { @@ -198,17 +198,17 @@ var LocationMenu = function(opts) { self.toggleMenu(); } else if (clickedOverlay == self.previousButton) { if (self.previousEnabled) { - Overlays.editOverlay(clickedOverlay, { color: activeColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor }); } } else if (clickedOverlay == self.nextButton) { if (self.nextEnabled) { - Overlays.editOverlay(clickedOverlay, { color: activeColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor }); } } else { for (var i = 0; i < self.menuItems.length; i++) { if (clickedOverlay == self.menuItems[i].overlay) { if (self.menuItems[i].location != null) { - Overlays.editOverlay(clickedOverlay, { color: activeColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: activeColor }); } break; } @@ -221,19 +221,19 @@ var LocationMenu = function(opts) { if (clickedOverlay == self.previousButton) { if (self.previousEnabled) { - Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor }); self.goToPage(self.page - 1); } } else if (clickedOverlay == self.nextButton) { if (self.nextEnabled) { - Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor }); self.goToPage(self.page + 1); } } else { for (var i = 0; i < self.menuItems.length; i++) { if (clickedOverlay == self.menuItems[i].overlay) { if (self.menuItems[i].location != null) { - Overlays.editOverlay(clickedOverlay, { color: inactiveColor }); + Overlays.editOverlay(clickedOverlay, { backgroundColor: inactiveColor }); var location = self.menuItems[i].location; Window.location = "hifi://" + location.domain + "/" + location.x + "," + location.y + "," + location.z; From 123773a8e384e56e52c120ab78fa4efced831ab1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Jun 2014 12:20:05 -0700 Subject: [PATCH 03/15] Add default background color and initialize property --- interface/src/ui/overlays/Overlay.cpp | 2 +- interface/src/ui/overlays/Overlay.h | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 1 + interface/src/ui/overlays/TextOverlay.h | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 8ec7cbace1..bc7096c471 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -22,7 +22,7 @@ Overlay::Overlay() : _parent(NULL), _alpha(DEFAULT_ALPHA), - _color(DEFAULT_BACKGROUND_COLOR), + _color(DEFAULT_OVERLAY_COLOR), _visible(true), _anchor(NO_ANCHOR) { diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 7667b3d3fd..f8d6400bf6 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -21,7 +21,7 @@ #include // for xColor -const xColor DEFAULT_BACKGROUND_COLOR = { 255, 255, 255 }; +const xColor DEFAULT_OVERLAY_COLOR = { 255, 255, 255 }; const float DEFAULT_ALPHA = 0.7f; class Overlay : public QObject { diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 5fc98810be..691179ec54 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -18,6 +18,7 @@ #include "ui/TextRenderer.h" TextOverlay::TextOverlay() : + _backgroundColor(DEFAULT_BACKGROUND_COLOR), _leftMargin(DEFAULT_MARGIN), _topMargin(DEFAULT_MARGIN), _fontSize(DEFAULT_FONTSIZE) diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 6de415dcc7..6484b6a38f 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -28,6 +28,7 @@ #include "Overlay.h" #include "Overlay2D.h" +const xColor DEFAULT_BACKGROUND_COLOR = { 0, 0, 0 }; const int DEFAULT_MARGIN = 10; const int DEFAULT_FONTSIZE = 11; From 154eb0433635fcf84a5748ef136fb2f5f359bb62 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Jul 2014 17:13:39 -0700 Subject: [PATCH 04/15] Working on sending large deltas as reliable messages. --- .../src/metavoxels/MetavoxelServer.cpp | 4 +- libraries/metavoxels/src/Bitstream.cpp | 20 ++- libraries/metavoxels/src/Bitstream.h | 20 +++ .../metavoxels/src/DatagramSequencer.cpp | 32 +++-- libraries/metavoxels/src/DatagramSequencer.h | 29 +++- libraries/metavoxels/src/Endpoint.cpp | 30 +++-- libraries/metavoxels/src/Endpoint.h | 5 +- libraries/metavoxels/src/MetavoxelData.cpp | 14 ++ libraries/metavoxels/src/MetavoxelData.h | 7 + tests/metavoxels/src/MetavoxelTests.cpp | 124 ++++++++++-------- tests/metavoxels/src/MetavoxelTests.h | 8 +- 11 files changed, 204 insertions(+), 89 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index d0c0d4c781..e7e06c96d0 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -94,8 +94,8 @@ MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServe _server(server) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); - connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), - SLOT(handleMessage(const QVariant&))); + connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), + SLOT(handleMessage(const QVariant&, Bitstream&))); } void MetavoxelSession::update() { diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index d18903f923..4a86344c8c 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -127,6 +127,7 @@ Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, Generic _underlying(underlying), _byte(0), _position(0), + _bytesRemaining(INT_MAX), _metadataType(metadataType), _genericsMode(genericsMode), _objectStreamerStreamer(*this), @@ -193,13 +194,16 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) { void Bitstream::flush() { if (_position != 0) { _underlying << _byte; - reset(); + _bytesRemaining--; + _byte = 0; + _position = 0; } } void Bitstream::reset() { _byte = 0; _position = 0; + _bytesRemaining = INT_MAX; } Bitstream::WriteMappings Bitstream::getAndResetWriteMappings() { @@ -1122,7 +1126,7 @@ Bitstream& Bitstream::operator>(ObjectStreamerPointer& streamer) { } if (_metadataType == NO_METADATA) { if (!metaObject) { - qWarning() << "Unknown class name:" << className; + throw BitstreamException(QString("Unknown class name: ") + className); } return *this; } @@ -1232,7 +1236,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { } if (_metadataType == NO_METADATA) { if (!baseStreamer) { - qWarning() << "Unknown type name:" << typeName; + throw BitstreamException(QString("Unknown type name: ") + typeName); } return *this; } @@ -1240,7 +1244,7 @@ Bitstream& Bitstream::operator>(TypeStreamerPointer& streamer) { *this >> category; if (category == TypeStreamer::SIMPLE_CATEGORY) { if (!streamer) { - qWarning() << "Unknown type name:" << typeName; + throw BitstreamException(QString("Unknown type name: ") + typeName); } return *this; } @@ -1441,7 +1445,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { _objectStreamerStreamer >> objectStreamer; if (delta) { if (!reference) { - qWarning() << "Delta without reference" << id << originID; + throw BitstreamException(QString("Delta without reference [id=%1, originID=%2]").arg(id).arg(originID)); } objectStreamer->readRawDelta(*this, reference.data(), pointer.data()); } else { @@ -1451,7 +1455,7 @@ Bitstream& Bitstream::operator>(SharedObjectPointer& object) { QObject* rawObject; if (delta) { if (!reference) { - qWarning() << "Delta without reference" << id << originID; + throw BitstreamException(QString("Delta without reference [id=%1, originID=%2]").arg(id).arg(originID)); } readRawDelta(rawObject, (const QObject*)reference.data()); } else { @@ -1682,6 +1686,10 @@ const TypeStreamer* Bitstream::createInvalidTypeStreamer() { return streamer; } +BitstreamException::BitstreamException(const QString& description) : + _description(description) { +} + QJsonValue JSONWriter::getData(bool value) { return value; } diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index e32f93dbe2..d900b34847 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -329,6 +329,12 @@ public: /// Resets to the initial state. void reset(); + /// Sets the number of "bytes remaining," which will be decremented with each byte written. + void setBytesRemaining(int bytesRemaining) { _bytesRemaining = bytesRemaining; } + + /// Returns the number of bytes remaining. + int getBytesRemaining() const { return _bytesRemaining; } + /// Returns the set of transient mappings gathered during writing and resets them. WriteMappings getAndResetWriteMappings(); @@ -508,6 +514,7 @@ private: QDataStream& _underlying; quint8 _byte; int _position; + int _bytesRemaining; MetadataType _metadataType; GenericsMode _genericsMode; @@ -823,6 +830,19 @@ template inline Bitstream& Bitstream::operator>>(QHash& return *this; } +/// Thrown for unrecoverable errors. +class BitstreamException { +public: + + BitstreamException(const QString& description); + + const QString& getDescription() const { return _description; } + +private: + + QString _description; +}; + /// Provides a means of writing Bitstream-able data to JSON rather than the usual binary format in a manner that allows it to /// be manipulated and re-read, converted to binary, etc. To use, create a JSONWriter, stream values in using the << operator, /// and call getDocument to obtain the JSON data. diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index eb02497321..3b16a829e6 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -253,6 +253,8 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) { // record the receipt ReceiveRecord record = { _incomingPacketNumber, _inputStream.getAndResetReadMappings(), newHighPriorityMessages }; _receiveRecords.append(record); + + emit receiveRecorded(); } void DatagramSequencer::sendClearSharedObjectMessage(int id) { @@ -364,6 +366,8 @@ void DatagramSequencer::sendPacket(const QByteArray& packet, const QVector().id); @@ -700,7 +712,7 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o _dataStream.setByteOrder(QDataStream::LittleEndian); connect(&_bitstream, SIGNAL(sharedObjectCleared(int)), SLOT(sendClearSharedObjectMessage(int))); - connect(this, SIGNAL(receivedMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); + connect(this, SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); } void ReliableChannel::writeData(QDataStream& out, int bytes, QVector& spans) { @@ -843,9 +855,9 @@ void ReliableChannel::readData(QDataStream& in) { _dataStream.skipRawData(sizeof(quint32)); QVariant message; _bitstream >> message; + emit receivedMessage(message, _bitstream); _bitstream.reset(); _bitstream.persistAndResetReadMappings(); - emit receivedMessage(message); continue; } } diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index aa8b6907ff..09d2f834ef 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -126,9 +126,15 @@ signals: /// Emitted when a packet is available to read. void readyToRead(Bitstream& input); - /// Emitted when we've received a high-priority message + /// Emitted when we've received a high-priority message. void receivedHighPriorityMessage(const QVariant& data); + /// Emitted when we've recorded the transmission of a packet. + void sendRecorded(); + + /// Emitted when we've recorded the receipt of a packet (that is, at the end of packet processing). + void receiveRecorded(); + /// Emitted when a sent packet has been acknowledged by the remote side. /// \param index the index of the packet in our list of send records void sendAcknowledged(int index); @@ -336,22 +342,36 @@ public: /// Returns the number of bytes available to read from this channel. int getBytesAvailable() const; + /// Returns the offset, which represents the total number of bytes acknowledged + /// (on the write end) or received completely (on the read end). + int getOffset() const { return _offset; } + + /// Returns the total number of bytes written to this channel. + int getBytesWritten() const { return _offset + _buffer.pos(); } + /// Sets whether we expect to write/read framed messages. void setMessagesEnabled(bool enabled) { _messagesEnabled = enabled; } bool getMessagesEnabled() const { return _messagesEnabled; } - /// Sends a framed message on this channel. + /// Starts a framed message on this channel. + void startMessage(); + + /// Ends a framed message on this channel. + void endMessage(); + + /// Sends a framed message on this channel (convenience function that calls startMessage, + /// writes the message to the bitstream, then calls endMessage). void sendMessage(const QVariant& message); signals: /// Fired when a framed message has been received on this channel. - void receivedMessage(const QVariant& message); + void receivedMessage(const QVariant& message, Bitstream& in); private slots: void sendClearSharedObjectMessage(int id); - void handleMessage(const QVariant& message); + void handleMessage(const QVariant& message, Bitstream& in); private: @@ -381,6 +401,7 @@ private: int _writePositionResetPacketNumber; SpanList _acknowledged; bool _messagesEnabled; + int _messageLengthPlaceholder; }; #endif // hifi_DatagramSequencer_h diff --git a/libraries/metavoxels/src/Endpoint.cpp b/libraries/metavoxels/src/Endpoint.cpp index c656054504..666ffe52d9 100644 --- a/libraries/metavoxels/src/Endpoint.cpp +++ b/libraries/metavoxels/src/Endpoint.cpp @@ -19,6 +19,8 @@ Endpoint::Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendReco connect(&_sequencer, SIGNAL(readyToWrite(const QByteArray&)), SLOT(sendDatagram(const QByteArray&))); connect(&_sequencer, SIGNAL(readyToRead(Bitstream&)), SLOT(readMessage(Bitstream&))); + connect(&_sequencer, SIGNAL(sendRecorded()), SLOT(recordSend())); + connect(&_sequencer, SIGNAL(receiveRecorded()), SLOT(recordReceive())); connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(clearSendRecordsBefore(int))); connect(&_sequencer, SIGNAL(receiveAcknowledged(int)), SLOT(clearReceiveRecordsBefore(int))); @@ -40,9 +42,6 @@ void Endpoint::update() { Bitstream& out = _sequencer.startPacket(); writeUpdateMessage(out); _sequencer.endPacket(); - - // record the send - _sendRecords.append(maybeCreateSendRecord()); } int Endpoint::parseData(const QByteArray& packet) { @@ -59,8 +58,21 @@ void Endpoint::readMessage(Bitstream& in) { QVariant message; in >> message; handleMessage(message, in); - - // record the receipt +} + +void Endpoint::handleMessage(const QVariant& message, Bitstream& in) { + if (message.userType() == QMetaType::QVariantList) { + foreach (const QVariant& element, message.toList()) { + handleMessage(element, in); + } + } +} + +void Endpoint::recordSend() { + _sendRecords.append(maybeCreateSendRecord()); +} + +void Endpoint::recordReceive() { _receiveRecords.append(maybeCreateReceiveRecord()); } @@ -84,14 +96,6 @@ void Endpoint::writeUpdateMessage(Bitstream& out) { out << QVariant(); } -void Endpoint::handleMessage(const QVariant& message, Bitstream& in) { - if (message.userType() == QMetaType::QVariantList) { - foreach (const QVariant& element, message.toList()) { - handleMessage(element, in); - } - } -} - PacketRecord* Endpoint::maybeCreateSendRecord() const { return NULL; } diff --git a/libraries/metavoxels/src/Endpoint.h b/libraries/metavoxels/src/Endpoint.h index d253a69ded..b1f468531b 100644 --- a/libraries/metavoxels/src/Endpoint.h +++ b/libraries/metavoxels/src/Endpoint.h @@ -37,6 +37,10 @@ protected slots: virtual void sendDatagram(const QByteArray& data); virtual void readMessage(Bitstream& in); + virtual void handleMessage(const QVariant& message, Bitstream& in); + + void recordSend(); + void recordReceive(); void clearSendRecordsBefore(int index); void clearReceiveRecordsBefore(int index); @@ -44,7 +48,6 @@ protected slots: protected: virtual void writeUpdateMessage(Bitstream& out); - virtual void handleMessage(const QVariant& message, Bitstream& in); virtual PacketRecord* maybeCreateSendRecord() const; virtual PacketRecord* maybeCreateReceiveRecord() const; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 2d61ede796..43206588cc 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -681,6 +681,12 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } +void MetavoxelStreamState::checkByteLimitExceeded() { + if (stream.getBytesRemaining() < 0) { + throw ByteLimitExceededException(); + } +} + MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) : _referenceCount(1) { @@ -772,11 +778,13 @@ void MetavoxelNode::read(MetavoxelStreamState& state) { void MetavoxelNode::write(MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { state.attribute->write(state.stream, _attributeValue, true); + state.checkByteLimitExceeded(); return; } bool leaf = isLeaf(); state.stream << leaf; state.attribute->write(state.stream, _attributeValue, leaf); + state.checkByteLimitExceeded(); if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, state.stream, state.lod, state.referenceLOD }; @@ -830,11 +838,13 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true); + state.checkByteLimitExceeded(); return; } bool leaf = isLeaf(); state.stream << leaf; state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf); + state.checkByteLimitExceeded(); if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, state.stream, state.lod, state.referenceLOD }; @@ -897,6 +907,7 @@ void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { bool subdivideReference = state.shouldSubdivideReference(); if (!subdivideReference) { state.stream << leaf; + state.checkByteLimitExceeded(); } if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, @@ -921,6 +932,7 @@ void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { if (static_cast(object.data())->testAndSetVisited()) { state.stream << object; + state.checkByteLimitExceeded(); } } if (!state.shouldSubdivide() || isLeaf()) { @@ -940,11 +952,13 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS foreach (const SharedObjectPointer& object, oldSet) { if (static_cast(object.data())->testAndSetVisited() && !newSet.contains(object)) { state.stream << object; + state.checkByteLimitExceeded(); } } foreach (const SharedObjectPointer& object, newSet) { if (static_cast(object.data())->testAndSetVisited() && !oldSet.contains(object)) { state.stream << object; + state.checkByteLimitExceeded(); } } if (isLeaf() || !state.shouldSubdivide()) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 6a7ba33eb5..a0b0b6ef47 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -164,6 +164,13 @@ public: bool becameSubdivided() const; void setMinimum(const glm::vec3& lastMinimum, int index); + + /// Throws ByteLimitExceededException if the stream has fewer than zero bytes remaining. + void checkByteLimitExceeded(); +}; + +/// Thrown when we have exceeded the byte limit in writing. +class ByteLimitExceededException { }; /// A single node within a metavoxel layer. diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 61ab664310..5096f2b733 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -646,11 +646,14 @@ TestEndpoint::TestEndpoint(Mode mode) : Endpoint(SharedNodePointer(), new TestSendRecord(), new TestReceiveRecord()), _mode(mode), _highPriorityMessagesToSend(0.0f), - _reliableMessagesToSend(0.0f) { + _reliableMessagesToSend(0.0f), + _reliableDeltaReceivedOffset(0) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); - + connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), + SLOT(handleReliableMessage(const QVariant&, Bitstream&))); + if (mode == METAVOXEL_CLIENT_MODE) { _lod = MetavoxelLOD(glm::vec3(), 0.01f); return; @@ -663,19 +666,16 @@ TestEndpoint::TestEndpoint(Mode mode) : _data.guide(visitor); qDebug() << "Created" << visitor.leafCount << "base leaves"; - _data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), new Sphere()); + //_data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), new Sphere()); _sphere = new Sphere(); static_cast(_sphere.data())->setScale(0.01f); - _data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), _sphere); + //_data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), _sphere); return; } // create the object that represents out delta-encoded state _localState = new TestSharedObjectA(); - connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&)), - SLOT(handleReliableMessage(const QVariant&))); - ReliableChannel* secondInput = _sequencer.getReliableInputChannel(1); secondInput->setMessagesEnabled(false); connect(&secondInput->getBuffer(), SIGNAL(readyRead()), SLOT(readReliableChannel())); @@ -867,9 +867,6 @@ bool TestEndpoint::simulate(int iterationNumber) { maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent); maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent); - - // record the send - _sendRecords.append(maybeCreateSendRecord()); } return false; @@ -880,9 +877,6 @@ bool TestEndpoint::simulate(int iterationNumber) { out << QVariant::fromValue(state); _sequencer.endPacket(); - // record the send - _sendRecords.append(maybeCreateSendRecord()); - } else if (_mode == METAVOXEL_SERVER_MODE) { // make a random change MutateVisitor visitor; @@ -899,7 +893,7 @@ bool TestEndpoint::simulate(int iterationNumber) { newSphere->setTranslation(newSphere->getTranslation() + glm::vec3(randFloatInRange(-0.01f, 0.01f), randFloatInRange(-0.01f, 0.01f), randFloatInRange(-0.01f, 0.01f))); } - _data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), oldSphere, _sphere); + //_data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), oldSphere, _sphere); spannerMutationsPerformed++; } @@ -907,15 +901,43 @@ bool TestEndpoint::simulate(int iterationNumber) { if (!_lod.isValid()) { return false; } + // if we're sending a reliable delta, wait until it's acknowledged + if (_reliableDeltaReceivedOffset > 0) { + if (_sequencer.getReliableOutputChannel()->getOffset() < _reliableDeltaReceivedOffset) { + Bitstream& out = _sequencer.startPacket(); + out << QVariant(); + _sequencer.endPacket(); + return false; + } + _reliableDeltaReceivedOffset = 0; + _reliableDeltaData = MetavoxelData(); + } Bitstream& out = _sequencer.startPacket(); out << QVariant::fromValue(MetavoxelDeltaMessage()); PacketRecord* sendRecord = getLastAcknowledgedSendRecord(); - _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); - _sequencer.endPacket(); - - // record the send - _sendRecords.append(maybeCreateSendRecord()); - + out.setBytesRemaining(_sequencer.getMaxPacketSize()); + try { + _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + _sequencer.endPacket(); + + } catch (const ByteLimitExceededException& exception) { + _sequencer.cancelPacket(); + + // we need to send the delta on the reliable channel + ReliableChannel* channel = _sequencer.getReliableOutputChannel(); + channel->startMessage(); + channel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); + _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), channel->getBitstream(), _lod); + channel->endMessage(); + + _reliableDeltaReceivedOffset = channel->getBytesWritten(); + _reliableDeltaData = _data; + _reliableDeltaLOD = _lod; + + Bitstream& out = _sequencer.startPacket(); + out << QVariant(); + _sequencer.endPacket(); + } } else { // enqueue some number of high priority messages const float MIN_HIGH_PRIORITY_MESSAGES = 0.0f; @@ -957,9 +979,6 @@ bool TestEndpoint::simulate(int iterationNumber) { qDebug() << message; return true; } - - // record the send - _sendRecords.append(maybeCreateSendRecord()); } maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent); maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent); @@ -995,7 +1014,7 @@ void TestEndpoint::sendDatagram(const QByteArray& datagram) { // some are received out of order const float REORDER_PROBABILITY = 0.1f; if (randFloat() < REORDER_PROBABILITY * probabilityMultiplier) { - const int MIN_DELAY = 1; + const int MIN_DELAY = 2; const int MAX_DELAY = 5; // have to copy the datagram; the one we're passed is a reference to a shared buffer _delayedDatagrams.append(ByteArrayIntPair(QByteArray(datagram.constData(), datagram.size()), @@ -1008,58 +1027,32 @@ void TestEndpoint::sendDatagram(const QByteArray& datagram) { } } - _other->parseData(datagram); + _delayedDatagrams.append(ByteArrayIntPair(QByteArray(datagram.constData(), datagram.size()), 1)); } void TestEndpoint::readMessage(Bitstream& in) { if (_mode == CONGESTION_MODE) { QVariant message; in >> message; - - // record the receipt - _receiveRecords.append(maybeCreateReceiveRecord()); return; } if (_mode == METAVOXEL_CLIENT_MODE) { QVariant message; in >> message; handleMessage(message, in); - - // deep-compare data to sent version - int packetNumber = _sequencer.getIncomingPacketNumber(); - foreach (PacketRecord* record, _other->_sendRecords) { - TestSendRecord* sendRecord = static_cast(record); - if (sendRecord->getPacketNumber() == packetNumber) { - if (!sendRecord->getData().deepEquals(_data, getLastAcknowledgedSendRecord()->getLOD())) { - qDebug() << "Sent/received metavoxel data mismatch."; - exit(true); - } - break; - } - } - - // record the receipt - _receiveRecords.append(maybeCreateReceiveRecord()); return; } if (_mode == METAVOXEL_SERVER_MODE) { QVariant message; in >> message; handleMessage(message, in); - - // record the receipt - _receiveRecords.append(maybeCreateReceiveRecord()); return; } - SequencedTestMessage message; in >> message; _remoteState = message.state; - // record the receipt - _receiveRecords.append(maybeCreateReceiveRecord()); - for (QList::iterator it = _other->_unreliableMessagesSent.begin(); it != _other->_unreliableMessagesSent.end(); it++) { if (it->sequenceNumber == message.sequenceNumber) { @@ -1089,6 +1082,7 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { } else if (userType == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD()); + compareMetavoxelData(); } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { @@ -1098,6 +1092,9 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { } PacketRecord* TestEndpoint::maybeCreateSendRecord() const { + if (_reliableDeltaReceivedOffset > 0) { + return new TestSendRecord(_reliableDeltaLOD, _reliableDeltaData, _localState, _sequencer.getOutgoingPacketNumber()); + } return new TestSendRecord(_lod, (_mode == METAVOXEL_CLIENT_MODE) ? MetavoxelData() : _data, _localState, _sequencer.getOutgoingPacketNumber()); } @@ -1121,7 +1118,13 @@ void TestEndpoint::handleHighPriorityMessage(const QVariant& message) { highPriorityMessagesReceived++; } -void TestEndpoint::handleReliableMessage(const QVariant& message) { +void TestEndpoint::handleReliableMessage(const QVariant& message, Bitstream& in) { + if (message.userType() == MetavoxelDeltaMessage::Type) { + PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); + _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD()); + compareMetavoxelData(); + return; + } if (message.userType() == ClearSharedObjectMessage::Type || message.userType() == ClearMainChannelSharedObjectMessage::Type) { return; @@ -1150,6 +1153,23 @@ void TestEndpoint::readReliableChannel() { streamedBytesReceived += bytes.size(); } +void TestEndpoint::compareMetavoxelData() { + // deep-compare data to sent version + int packetNumber = _sequencer.getIncomingPacketNumber(); + foreach (PacketRecord* record, _other->_sendRecords) { + TestSendRecord* sendRecord = static_cast(record); + if (sendRecord->getPacketNumber() == packetNumber) { + if (!sendRecord->getData().deepEquals(_data, getLastAcknowledgedSendRecord()->getLOD())) { + qDebug() << "Sent/received metavoxel data mismatch."; + exit(true); + } + return; + } + } + qDebug() << "Received metavoxel data with no corresponding send." << packetNumber; + exit(true); +} + TestSharedObjectA::TestSharedObjectA(float foo, TestEnum baz, TestFlags bong) : _foo(foo), _baz(baz), diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index 476a8c6295..e946dfddaf 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -64,11 +64,13 @@ protected: private slots: void handleHighPriorityMessage(const QVariant& message); - void handleReliableMessage(const QVariant& message); + void handleReliableMessage(const QVariant& message, Bitstream& in); void readReliableChannel(); private: + void compareMetavoxelData(); + Mode _mode; SharedObjectPointer _localState; @@ -94,6 +96,10 @@ private: float _reliableMessagesToSend; QVariantList _reliableMessagesSent; CircularBuffer _dataStreamed; + + int _reliableDeltaReceivedOffset; + MetavoxelData _reliableDeltaData; + MetavoxelLOD _reliableDeltaLOD; }; /// A simple shared object. From 282c62a083610238e4203b3a81f270e795c01fd4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 2 Jul 2014 18:49:40 -0700 Subject: [PATCH 05/15] Handle LODs correctly (?) for reliable deltas. --- libraries/metavoxels/src/MetavoxelMessages.h | 7 +++++++ tests/metavoxels/src/MetavoxelTests.cpp | 21 +++++++++++++------- tests/metavoxels/src/MetavoxelTests.h | 2 ++ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelMessages.h b/libraries/metavoxels/src/MetavoxelMessages.h index 8f819fe3d8..b822f1c561 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.h +++ b/libraries/metavoxels/src/MetavoxelMessages.h @@ -61,6 +61,13 @@ class MetavoxelDeltaMessage { DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaMessage) +/// A message indicating that metavoxel delta information is being sent on a reliable channel. +class MetavoxelDeltaPendingMessage { + STREAMABLE +}; + +DECLARE_STREAMABLE_METATYPE(MetavoxelDeltaPendingMessage) + /// A simple streamable edit. class MetavoxelEditMessage { STREAMABLE diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 5096f2b733..7c278f3c2f 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -647,7 +647,8 @@ TestEndpoint::TestEndpoint(Mode mode) : _mode(mode), _highPriorityMessagesToSend(0.0f), _reliableMessagesToSend(0.0f), - _reliableDeltaReceivedOffset(0) { + _reliableDeltaReceivedOffset(0), + _reliableDeltaPending(false) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); @@ -905,7 +906,7 @@ bool TestEndpoint::simulate(int iterationNumber) { if (_reliableDeltaReceivedOffset > 0) { if (_sequencer.getReliableOutputChannel()->getOffset() < _reliableDeltaReceivedOffset) { Bitstream& out = _sequencer.startPacket(); - out << QVariant(); + out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); _sequencer.endPacket(); return false; } @@ -935,7 +936,7 @@ bool TestEndpoint::simulate(int iterationNumber) { _reliableDeltaLOD = _lod; Bitstream& out = _sequencer.startPacket(); - out << QVariant(); + out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); _sequencer.endPacket(); } } else { @@ -1081,9 +1082,15 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { } else if (userType == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD()); + _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, + _dataLOD = getLastAcknowledgedSendRecord()->getLOD()); compareMetavoxelData(); + } else if (userType == MetavoxelDeltaPendingMessage::Type) { + if (!_reliableDeltaPending) { + _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); + _reliableDeltaPending = true; + } } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { handleMessage(element, in); @@ -1100,8 +1107,7 @@ PacketRecord* TestEndpoint::maybeCreateSendRecord() const { } PacketRecord* TestEndpoint::maybeCreateReceiveRecord() const { - return new TestReceiveRecord(getLastAcknowledgedSendRecord()->getLOD(), - (_mode == METAVOXEL_SERVER_MODE) ? MetavoxelData() : _data, _remoteState); + return new TestReceiveRecord(_dataLOD, (_mode == METAVOXEL_SERVER_MODE) ? MetavoxelData() : _data, _remoteState); } void TestEndpoint::handleHighPriorityMessage(const QVariant& message) { @@ -1121,8 +1127,9 @@ void TestEndpoint::handleHighPriorityMessage(const QVariant& message) { void TestEndpoint::handleReliableMessage(const QVariant& message, Bitstream& in) { if (message.userType() == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD()); + _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _dataLOD = _reliableDeltaLOD); compareMetavoxelData(); + _reliableDeltaPending = false; return; } if (message.userType() == ClearSharedObjectMessage::Type || diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index e946dfddaf..f451b5e8b6 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -77,6 +77,7 @@ private: SharedObjectPointer _remoteState; MetavoxelData _data; + MetavoxelLOD _dataLOD; MetavoxelLOD _lod; SharedObjectPointer _sphere; @@ -100,6 +101,7 @@ private: int _reliableDeltaReceivedOffset; MetavoxelData _reliableDeltaData; MetavoxelLOD _reliableDeltaLOD; + bool _reliableDeltaPending; }; /// A simple shared object. From da32c6e89bf812b47cb3cf8b9ff7aa79311756f6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 3 Jul 2014 17:29:10 -0700 Subject: [PATCH 06/15] Push persistent mappings into reliable delta channel before sending and pull transient mappings out after sending. --- libraries/metavoxels/src/Bitstream.cpp | 20 ++++++ libraries/metavoxels/src/Bitstream.h | 32 +++++++++ .../metavoxels/src/DatagramSequencer.cpp | 18 ++++- libraries/metavoxels/src/DatagramSequencer.h | 11 ++++ tests/metavoxels/src/MetavoxelTests.cpp | 65 ++++++++++++------- tests/metavoxels/src/MetavoxelTests.h | 4 +- 6 files changed, 123 insertions(+), 27 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 4a86344c8c..459a12dc15 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -278,6 +278,26 @@ void Bitstream::persistAndResetReadMappings() { persistReadMappings(getAndResetReadMappings()); } +void Bitstream::copyPersistentMappings(const Bitstream& other) { + _objectStreamerStreamer.copyPersistentMappings(other._objectStreamerStreamer); + _typeStreamerStreamer.copyPersistentMappings(other._typeStreamerStreamer); + _attributeStreamer.copyPersistentMappings(other._attributeStreamer); + _scriptStringStreamer.copyPersistentMappings(other._scriptStringStreamer); + _sharedObjectStreamer.copyPersistentMappings(other._sharedObjectStreamer); + _sharedObjectReferences = other._sharedObjectReferences; + _weakSharedObjectHash = other._weakSharedObjectHash; +} + +void Bitstream::clearPersistentMappings() { + _objectStreamerStreamer.clearPersistentMappings(); + _typeStreamerStreamer.clearPersistentMappings(); + _attributeStreamer.clearPersistentMappings(); + _scriptStringStreamer.clearPersistentMappings(); + _sharedObjectStreamer.clearPersistentMappings(); + _sharedObjectReferences.clear(); + _weakSharedObjectHash.clear(); +} + void Bitstream::clearSharedObject(int id) { SharedObjectPointer object = _sharedObjectStreamer.takePersistentValue(id); if (object) { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index d900b34847..97f1b70ff0 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -102,6 +102,9 @@ public: V takePersistentValue(int id) { V value = _persistentValues.take(id); _valueIDs.remove(value); return value; } + void copyPersistentMappings(const RepeatedValueStreamer& other); + void clearPersistentMappings(); + RepeatedValueStreamer& operator<<(K value); RepeatedValueStreamer& operator>>(V& value); @@ -199,6 +202,29 @@ template inline RepeatedValueStreamer& return *this; } +template inline void RepeatedValueStreamer::copyPersistentMappings( + const RepeatedValueStreamer& other) { + _lastPersistentID = other._lastPersistentID; + _idStreamer.setBitsFromValue(_lastPersistentID); + _persistentIDs = other._persistentIDs; + _transientOffsets.clear(); + _lastTransientOffset = 0; + _persistentValues = other._persistentValues; + _transientValues.clear(); + _valueIDs = other._valueIDs; +} + +template inline void RepeatedValueStreamer::clearPersistentMappings() { + _lastPersistentID = 0; + _idStreamer.setBitsFromValue(_lastPersistentID); + _persistentIDs.clear(); + _transientOffsets.clear(); + _lastTransientOffset = 0; + _persistentValues.clear(); + _transientValues.clear(); + _valueIDs.clear(); +} + /// A stream for bit-aligned data. Through a combination of code generation, reflection, macros, and templates, provides a /// serialization mechanism that may be used for both networking and persistent storage. For unreliable networking, the /// class provides a mapping system that resends mappings for ids until they are acknowledged (and thus persisted). For @@ -353,6 +379,12 @@ public: /// Immediately persists and resets the read mappings. void persistAndResetReadMappings(); + /// Copies the persistent mappings from the specified other stream. + void copyPersistentMappings(const Bitstream& other); + + /// Clears the persistent mappings for this stream. + void clearPersistentMappings(); + /// Returns a reference to the weak hash storing shared objects for this stream. const WeakSharedObjectHash& getWeakSharedObjectHash() const { return _weakSharedObjectHash; } diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 3b16a829e6..2ef3d0213c 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -276,6 +276,11 @@ void DatagramSequencer::handleHighPriorityMessage(const QVariant& data) { } } +void DatagramSequencer::clearReliableChannel(QObject* object) { + ReliableChannel* channel = static_cast(object); + (channel->isOutput() ? _reliableOutputChannels : _reliableInputChannels).remove(channel->getIndex()); +} + void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { // stop acknowledging the recorded packets while (!_receiveRecords.isEmpty() && _receiveRecords.first().packetNumber <= record.lastReceivedPacketNumber) { @@ -297,7 +302,10 @@ void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { // acknowledge the received spans foreach (const ChannelSpan& span, record.spans) { - getReliableOutputChannel(span.channel)->spanAcknowledged(span); + ReliableChannel* channel = _reliableOutputChannels.value(span.channel); + if (channel) { + channel->spanAcknowledged(span); + } } // increase the packet rate with every ack until we pass the slow start threshold; then, every round trip @@ -312,7 +320,10 @@ void DatagramSequencer::sendRecordAcknowledged(const SendRecord& record) { void DatagramSequencer::sendRecordLost(const SendRecord& record) { // notify the channels of their lost spans foreach (const ChannelSpan& span, record.spans) { - getReliableOutputChannel(span.channel)->spanLost(record.packetNumber, _outgoingPacketNumber + 1); + ReliableChannel* channel = _reliableOutputChannels.value(span.channel); + if (channel) { + channel->spanLost(record.packetNumber, _outgoingPacketNumber + 1); + } } // halve the rate and remember as threshold @@ -700,6 +711,7 @@ void ReliableChannel::handleMessage(const QVariant& message, Bitstream& in) { ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool output) : QObject(sequencer), _index(index), + _output(output), _dataStream(&_buffer), _bitstream(_dataStream), _priority(1.0f), @@ -713,6 +725,8 @@ ReliableChannel::ReliableChannel(DatagramSequencer* sequencer, int index, bool o connect(&_bitstream, SIGNAL(sharedObjectCleared(int)), SLOT(sendClearSharedObjectMessage(int))); connect(this, SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); + + sequencer->connect(this, SIGNAL(destroyed(QObject*)), SLOT(clearReliableChannel(QObject*))); } void ReliableChannel::writeData(QDataStream& out, int bytes, QVector& spans) { diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 09d2f834ef..32f645b13c 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -78,6 +78,12 @@ public: /// Returns the packet number of the last packet received (or the packet currently being assembled). int getIncomingPacketNumber() const { return _incomingPacketNumber; } + /// Returns a reference to the stream used to read packets. + Bitstream& getInputStream() { return _inputStream; } + + /// Returns a reference to the stream used to write packets. + Bitstream& getOutputStream() { return _outputStream; } + /// Returns the packet number of the sent packet at the specified index. int getSentPacketNumber(int index) const { return _sendRecords.at(index).packetNumber; } @@ -147,6 +153,7 @@ private slots: void sendClearSharedObjectMessage(int id); void handleHighPriorityMessage(const QVariant& data); + void clearReliableChannel(QObject* object); private: @@ -325,6 +332,9 @@ public: /// Returns the channel's index in the sequencer's channel map. int getIndex() const { return _index; } + /// Checks whether this is an output channel. + bool isOutput() const { return _output; } + /// Returns a reference to the buffer used to write/read data to/from this channel. CircularBuffer& getBuffer() { return _buffer; } @@ -390,6 +400,7 @@ private: void readData(QDataStream& in); int _index; + bool _output; CircularBuffer _buffer; CircularBuffer _assemblyBuffer; QDataStream _dataStream; diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 7c278f3c2f..cc2d34f180 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -642,13 +642,14 @@ TestReceiveRecord::TestReceiveRecord(const MetavoxelLOD& lod, _remoteState(remoteState) { } +const int RELIABLE_DELTA_CHANNEL_INDEX = 1; + TestEndpoint::TestEndpoint(Mode mode) : Endpoint(SharedNodePointer(), new TestSendRecord(), new TestReceiveRecord()), _mode(mode), _highPriorityMessagesToSend(0.0f), _reliableMessagesToSend(0.0f), - _reliableDeltaReceivedOffset(0), - _reliableDeltaPending(false) { + _reliableDeltaChannel(NULL) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleHighPriorityMessage(const QVariant&))); @@ -657,9 +658,13 @@ TestEndpoint::TestEndpoint(Mode mode) : if (mode == METAVOXEL_CLIENT_MODE) { _lod = MetavoxelLOD(glm::vec3(), 0.01f); + connect(_sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX), + SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleReliableMessage(const QVariant&, Bitstream&))); return; } if (mode == METAVOXEL_SERVER_MODE) { + connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(checkReliableDeltaReceived())); + _data.expand(); _data.expand(); @@ -667,11 +672,11 @@ TestEndpoint::TestEndpoint(Mode mode) : _data.guide(visitor); qDebug() << "Created" << visitor.leafCount << "base leaves"; - //_data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), new Sphere()); + _data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), new Sphere()); _sphere = new Sphere(); static_cast(_sphere.data())->setScale(0.01f); - //_data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), _sphere); + _data.insert(AttributeRegistry::getInstance()->getSpannersAttribute(), _sphere); return; } // create the object that represents out delta-encoded state @@ -894,7 +899,7 @@ bool TestEndpoint::simulate(int iterationNumber) { newSphere->setTranslation(newSphere->getTranslation() + glm::vec3(randFloatInRange(-0.01f, 0.01f), randFloatInRange(-0.01f, 0.01f), randFloatInRange(-0.01f, 0.01f))); } - //_data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), oldSphere, _sphere); + _data.replace(AttributeRegistry::getInstance()->getSpannersAttribute(), oldSphere, _sphere); spannerMutationsPerformed++; } @@ -903,15 +908,11 @@ bool TestEndpoint::simulate(int iterationNumber) { return false; } // if we're sending a reliable delta, wait until it's acknowledged - if (_reliableDeltaReceivedOffset > 0) { - if (_sequencer.getReliableOutputChannel()->getOffset() < _reliableDeltaReceivedOffset) { - Bitstream& out = _sequencer.startPacket(); - out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); - _sequencer.endPacket(); - return false; - } - _reliableDeltaReceivedOffset = 0; - _reliableDeltaData = MetavoxelData(); + if (_reliableDeltaChannel) { + Bitstream& out = _sequencer.startPacket(); + out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + _sequencer.endPacket(); + return false; } Bitstream& out = _sequencer.startPacket(); out << QVariant::fromValue(MetavoxelDeltaMessage()); @@ -925,13 +926,16 @@ bool TestEndpoint::simulate(int iterationNumber) { _sequencer.cancelPacket(); // we need to send the delta on the reliable channel - ReliableChannel* channel = _sequencer.getReliableOutputChannel(); - channel->startMessage(); - channel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); - _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), channel->getBitstream(), _lod); - channel->endMessage(); + _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getOutputStream()); + _reliableDeltaChannel->startMessage(); + _reliableDeltaChannel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); + _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), _reliableDeltaChannel->getBitstream(), _lod); + _reliableDeltaWriteMappings = _reliableDeltaChannel->getBitstream().getAndResetWriteMappings(); + _reliableDeltaChannel->getBitstream().clearPersistentMappings(); + _reliableDeltaChannel->endMessage(); - _reliableDeltaReceivedOffset = channel->getBytesWritten(); + _reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten(); _reliableDeltaData = _data; _reliableDeltaLOD = _lod; @@ -1087,9 +1091,10 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { compareMetavoxelData(); } else if (userType == MetavoxelDeltaPendingMessage::Type) { - if (!_reliableDeltaPending) { + if (!_reliableDeltaChannel) { + _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); - _reliableDeltaPending = true; } } else if (userType == QMetaType::QVariantList) { foreach (const QVariant& element, message.toList()) { @@ -1099,7 +1104,7 @@ void TestEndpoint::handleMessage(const QVariant& message, Bitstream& in) { } PacketRecord* TestEndpoint::maybeCreateSendRecord() const { - if (_reliableDeltaReceivedOffset > 0) { + if (_reliableDeltaChannel) { return new TestSendRecord(_reliableDeltaLOD, _reliableDeltaData, _localState, _sequencer.getOutgoingPacketNumber()); } return new TestSendRecord(_lod, (_mode == METAVOXEL_CLIENT_MODE) ? MetavoxelData() : _data, @@ -1128,8 +1133,10 @@ void TestEndpoint::handleReliableMessage(const QVariant& message, Bitstream& in) if (message.userType() == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _dataLOD = _reliableDeltaLOD); + _sequencer.getInputStream().persistReadMappings(in.getAndResetReadMappings()); + in.clearPersistentMappings(); compareMetavoxelData(); - _reliableDeltaPending = false; + _reliableDeltaChannel = NULL; return; } if (message.userType() == ClearSharedObjectMessage::Type || @@ -1160,6 +1167,16 @@ void TestEndpoint::readReliableChannel() { streamedBytesReceived += bytes.size(); } +void TestEndpoint::checkReliableDeltaReceived() { + if (!_reliableDeltaChannel || _reliableDeltaChannel->getOffset() < _reliableDeltaReceivedOffset) { + return; + } + _sequencer.getOutputStream().persistWriteMappings(_reliableDeltaWriteMappings); + _reliableDeltaWriteMappings = Bitstream::WriteMappings(); + _reliableDeltaData = MetavoxelData(); + _reliableDeltaChannel = NULL; +} + void TestEndpoint::compareMetavoxelData() { // deep-compare data to sent version int packetNumber = _sequencer.getIncomingPacketNumber(); diff --git a/tests/metavoxels/src/MetavoxelTests.h b/tests/metavoxels/src/MetavoxelTests.h index f451b5e8b6..5d719ccfdf 100644 --- a/tests/metavoxels/src/MetavoxelTests.h +++ b/tests/metavoxels/src/MetavoxelTests.h @@ -66,6 +66,7 @@ private slots: void handleHighPriorityMessage(const QVariant& message); void handleReliableMessage(const QVariant& message, Bitstream& in); void readReliableChannel(); + void checkReliableDeltaReceived(); private: @@ -98,10 +99,11 @@ private: QVariantList _reliableMessagesSent; CircularBuffer _dataStreamed; + ReliableChannel* _reliableDeltaChannel; int _reliableDeltaReceivedOffset; MetavoxelData _reliableDeltaData; MetavoxelLOD _reliableDeltaLOD; - bool _reliableDeltaPending; + Bitstream::WriteMappings _reliableDeltaWriteMappings; }; /// A simple shared object. From e15f003639819234e5b6e8021e8dd11588119ae9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Jul 2014 11:08:43 -0700 Subject: [PATCH 07/15] Bring reliable delta streaming code over from test. --- .../src/metavoxels/MetavoxelServer.cpp | 61 ++++++++++++++++--- .../src/metavoxels/MetavoxelServer.h | 8 ++- libraries/metavoxels/src/Endpoint.h | 3 + .../metavoxels/src/MetavoxelClientManager.cpp | 31 ++++++++-- .../metavoxels/src/MetavoxelClientManager.h | 4 ++ tests/metavoxels/src/MetavoxelTests.cpp | 2 - 6 files changed, 91 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index e7e06c96d0..a01efddbf4 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -91,24 +91,56 @@ void MetavoxelServer::sendDeltas() { MetavoxelSession::MetavoxelSession(const SharedNodePointer& node, MetavoxelServer* server) : Endpoint(node, new PacketRecord(), NULL), - _server(server) { + _server(server), + _reliableDeltaChannel(NULL) { connect(&_sequencer, SIGNAL(receivedHighPriorityMessage(const QVariant&)), SLOT(handleMessage(const QVariant&))); + connect(&_sequencer, SIGNAL(sendAcknowledged(int)), SLOT(checkReliableDeltaReceived())); connect(_sequencer.getReliableInputChannel(), SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); } void MetavoxelSession::update() { - // wait until we have a valid lod - if (_lod.isValid()) { - Endpoint::update(); + // wait until we have a valid lod before sending + if (!_lod.isValid()) { + return; } -} - -void MetavoxelSession::writeUpdateMessage(Bitstream& out) { + // if we're sending a reliable delta, wait until it's acknowledged + if (_reliableDeltaChannel) { + Bitstream& out = _sequencer.startPacket(); + out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + _sequencer.endPacket(); + return; + } + Bitstream& out = _sequencer.startPacket(); out << QVariant::fromValue(MetavoxelDeltaMessage()); PacketRecord* sendRecord = getLastAcknowledgedSendRecord(); - _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + out.setBytesRemaining(_sequencer.getMaxPacketSize()); + try { + _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + _sequencer.endPacket(); + + } catch (const ByteLimitExceededException& exception) { + _sequencer.cancelPacket(); + + // we need to send the delta on the reliable channel + _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getOutputStream()); + _reliableDeltaChannel->startMessage(); + _reliableDeltaChannel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); + _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), _reliableDeltaChannel->getBitstream(), _lod); + _reliableDeltaWriteMappings = _reliableDeltaChannel->getBitstream().getAndResetWriteMappings(); + _reliableDeltaChannel->getBitstream().clearPersistentMappings(); + _reliableDeltaChannel->endMessage(); + + _reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten(); + _reliableDeltaData = _server->getData(); + _reliableDeltaLOD = _lod; + + Bitstream& out = _sequencer.startPacket(); + out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); + _sequencer.endPacket(); + } } void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) { @@ -116,7 +148,8 @@ void MetavoxelSession::handleMessage(const QVariant& message, Bitstream& in) { } PacketRecord* MetavoxelSession::maybeCreateSendRecord() const { - return new PacketRecord(_lod, _server->getData()); + return _reliableDeltaChannel ? new PacketRecord(_reliableDeltaLOD, _reliableDeltaData) : + new PacketRecord(_lod, _server->getData()); } void MetavoxelSession::handleMessage(const QVariant& message) { @@ -134,3 +167,13 @@ void MetavoxelSession::handleMessage(const QVariant& message) { } } } + +void MetavoxelSession::checkReliableDeltaReceived() { + if (!_reliableDeltaChannel || _reliableDeltaChannel->getOffset() < _reliableDeltaReceivedOffset) { + return; + } + _sequencer.getOutputStream().persistWriteMappings(_reliableDeltaWriteMappings); + _reliableDeltaWriteMappings = Bitstream::WriteMappings(); + _reliableDeltaData = MetavoxelData(); + _reliableDeltaChannel = NULL; +} diff --git a/assignment-client/src/metavoxels/MetavoxelServer.h b/assignment-client/src/metavoxels/MetavoxelServer.h index d9b010e282..f2769f26f2 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.h +++ b/assignment-client/src/metavoxels/MetavoxelServer.h @@ -63,7 +63,6 @@ public: protected: - virtual void writeUpdateMessage(Bitstream& out); virtual void handleMessage(const QVariant& message, Bitstream& in); virtual PacketRecord* maybeCreateSendRecord() const; @@ -71,12 +70,19 @@ protected: private slots: void handleMessage(const QVariant& message); + void checkReliableDeltaReceived(); private: MetavoxelServer* _server; MetavoxelLOD _lod; + + ReliableChannel* _reliableDeltaChannel; + int _reliableDeltaReceivedOffset; + MetavoxelData _reliableDeltaData; + MetavoxelLOD _reliableDeltaLOD; + Bitstream::WriteMappings _reliableDeltaWriteMappings; }; #endif // hifi_MetavoxelServer_h diff --git a/libraries/metavoxels/src/Endpoint.h b/libraries/metavoxels/src/Endpoint.h index b1f468531b..3c681a7b98 100644 --- a/libraries/metavoxels/src/Endpoint.h +++ b/libraries/metavoxels/src/Endpoint.h @@ -24,6 +24,9 @@ class Endpoint : public NodeData { Q_OBJECT public: + + /// The index of the input/output channel used to transmit reliable deltas. + static const int RELIABLE_DELTA_CHANNEL_INDEX = 1; Endpoint(const SharedNodePointer& node, PacketRecord* baselineSendRecord = NULL, PacketRecord* baselineReceiveRecord = NULL); diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 008a477187..9abb5e9e5d 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -86,7 +86,11 @@ void MetavoxelClientManager::updateClient(MetavoxelClient* client) { MetavoxelClient::MetavoxelClient(const SharedNodePointer& node, MetavoxelClientManager* manager) : Endpoint(node, new PacketRecord(), new PacketRecord()), - _manager(manager) { + _manager(manager), + _reliableDeltaChannel(NULL) { + + connect(_sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX), + SIGNAL(receivedMessage(const QVariant&, Bitstream&)), SLOT(handleMessage(const QVariant&, Bitstream&))); } void MetavoxelClient::guide(MetavoxelVisitor& visitor) { @@ -124,19 +128,34 @@ void MetavoxelClient::readMessage(Bitstream& in) { } void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { - if (message.userType() == MetavoxelDeltaMessage::Type) { + int userType = message.userType(); + if (userType == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, getLastAcknowledgedSendRecord()->getLOD()); - + if (_reliableDeltaChannel) { + _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _dataLOD = _reliableDeltaLOD); + _sequencer.getInputStream().persistReadMappings(in.getAndResetReadMappings()); + in.clearPersistentMappings(); + _reliableDeltaChannel = NULL; + + } else { + _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, + _dataLOD = getLastAcknowledgedSendRecord()->getLOD()); + } + } else if (userType == MetavoxelDeltaPendingMessage::Type) { + if (!_reliableDeltaChannel) { + _reliableDeltaChannel = _sequencer.getReliableInputChannel(RELIABLE_DELTA_CHANNEL_INDEX); + _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getInputStream()); + _reliableDeltaLOD = getLastAcknowledgedSendRecord()->getLOD(); + } } else { Endpoint::handleMessage(message, in); } } PacketRecord* MetavoxelClient::maybeCreateSendRecord() const { - return new PacketRecord(_manager->getLOD()); + return new PacketRecord(_reliableDeltaChannel ? _reliableDeltaLOD : _manager->getLOD()); } PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const { - return new PacketRecord(getLastAcknowledgedSendRecord()->getLOD(), _data); + return new PacketRecord(_dataLOD, _data); } diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index dd11e871ec..9ab2e2c8b0 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -70,6 +70,10 @@ private: MetavoxelClientManager* _manager; MetavoxelData _data; + MetavoxelLOD _dataLOD; + + ReliableChannel* _reliableDeltaChannel; + MetavoxelLOD _reliableDeltaLOD; }; #endif // hifi_MetavoxelClientManager_h diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index cc2d34f180..48ce4716b7 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -642,8 +642,6 @@ TestReceiveRecord::TestReceiveRecord(const MetavoxelLOD& lod, _remoteState(remoteState) { } -const int RELIABLE_DELTA_CHANNEL_INDEX = 1; - TestEndpoint::TestEndpoint(Mode mode) : Endpoint(SharedNodePointer(), new TestSendRecord(), new TestReceiveRecord()), _mode(mode), From 982a50dbcf8d922af62d59e2f36fbae17f200d65 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Jul 2014 11:33:54 -0700 Subject: [PATCH 08/15] Remove multithread access from NetworkAccessManager for the time being --- .../networking/src/NetworkAccessManager.cpp | 150 +----------------- .../networking/src/NetworkAccessManager.h | 20 +-- 2 files changed, 10 insertions(+), 160 deletions(-) diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index 7e5ba3f66e..e92760d303 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -9,153 +9,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include -#include -#include +#include #include "NetworkAccessManager.h" +QThreadStorage networkAccessManagers; + NetworkAccessManager& NetworkAccessManager::getInstance() { - static NetworkAccessManager sharedInstance; - return sharedInstance; + if (!networkAccessManagers.hasLocalData()) { + networkAccessManagers.setLocalData(new NetworkAccessManager()); + } + + return *networkAccessManagers.localData(); } NetworkAccessManager::NetworkAccessManager() { - qRegisterMetaType(); } - -QNetworkReply* NetworkAccessManager::get(const QNetworkRequest& request) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "get", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request)); - return result; - } - return QNetworkAccessManager::get(request); -} - -QNetworkReply* NetworkAccessManager::head(const QNetworkRequest& request) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "head", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request)); - return result; - } - return QNetworkAccessManager::head(request); -} - -QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QIODevice* data) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "post", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(QIODevice*, data)); - return result; - } - return QNetworkAccessManager::post(request, data); -} - -QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, const QByteArray& data) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "post", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(const QByteArray, data)); - return result; - } - return QNetworkAccessManager::post(request, data); -} - -QNetworkReply* NetworkAccessManager::post(const QNetworkRequest& request, QHttpMultiPart* multiPart) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "post", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(QHttpMultiPart*, multiPart)); - return result; - } - return QNetworkAccessManager::post(request, multiPart); -} - -QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QIODevice* data) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "put", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(QIODevice*, data)); - return result; - } - return QNetworkAccessManager::put(request, data); -} - -QNetworkReply* NetworkAccessManager::put(const QNetworkRequest& request, QHttpMultiPart* multiPart) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "put", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(QHttpMultiPart*, multiPart)); - return result; - } - return QNetworkAccessManager::put(request, multiPart); -} - -QNetworkReply* NetworkAccessManager::put(const QNetworkRequest & request, const QByteArray & data) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "put", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(const QByteArray, data)); - return result; - } - return QNetworkAccessManager::put(request, data); -} - - -QNetworkReply* NetworkAccessManager::sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data) { - if (QThread::currentThread() != thread()) { - QNetworkReply* result; - QMetaObject::invokeMethod(this, - "sendCustomRequest", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QNetworkReply*, result), - Q_ARG(const QNetworkRequest, request), - Q_ARG(const QByteArray, verb), - Q_ARG(QIODevice*, data)); - return result; - } - return QNetworkAccessManager::sendCustomRequest(request, verb, data); -} - -void NetworkAccessManager::setCache(QAbstractNetworkCache* cache) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, - "setCache", - Qt::BlockingQueuedConnection, - Q_ARG(QAbstractNetworkCache*, cache)); - } - QNetworkAccessManager::setCache(cache); -} \ No newline at end of file diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index 1b49cc9dee..c1e22f5082 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -13,32 +13,16 @@ #define hifi_NetworkAccessManager_h #include -#include -#include -/// Wrapper around QNetworkAccessManager wo that we only use one instance -/// For any other method you should need, make sure to be on the right thread -/// or if it is not but is a slot, use QMetaObject::invokeMethod() -/// In the case what you want to call isn't a slot and you aren't on the same thread, -/// then add then method to the method to the wrapper with the Q_INVKABLE flag +/// Wrapper around QNetworkAccessManager to restrict at one instance by thread class NetworkAccessManager : public QNetworkAccessManager { Q_OBJECT public: static NetworkAccessManager& getInstance(); - Q_INVOKABLE QNetworkReply* get(const QNetworkRequest& request); - Q_INVOKABLE QNetworkReply* head(const QNetworkRequest& request); - Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QIODevice* data); - Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, const QByteArray& data); - Q_INVOKABLE QNetworkReply* post(const QNetworkRequest& request, QHttpMultiPart* multiPart); - Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QIODevice* data); - Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, QHttpMultiPart* multiPart); - Q_INVOKABLE QNetworkReply* put(const QNetworkRequest& request, const QByteArray& data); - Q_INVOKABLE QNetworkReply* sendCustomRequest(const QNetworkRequest& request, const QByteArray& verb, QIODevice* data = 0); - Q_INVOKABLE void setCache(QAbstractNetworkCache* cache); - private: NetworkAccessManager(); + Q_DISABLE_COPY(NetworkAccessManager) }; #endif // hifi_NetworkAccessManager_h \ No newline at end of file From a225df63f66e94aebd83a311752f6eb2bd61b62c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Jul 2014 11:40:03 -0700 Subject: [PATCH 09/15] Removed deprecated moveToThread() --- assignment-client/src/Agent.cpp | 1 - interface/src/Application.cpp | 5 ----- 2 files changed, 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 637bdca67f..0449e0d682 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -214,7 +214,6 @@ void Agent::run() { QNetworkDiskCache* cache = new QNetworkDiskCache(); QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "agentCache"); - cache->moveToThread(networkAccessManager.thread()); networkAccessManager.setCache(cache); qDebug() << "Downloading script at" << scriptURL.toString(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c263b71238..ace265ad4f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -316,12 +316,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); NetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - // Make sure cache on same thread than its parent (NetworkAccessManager) QNetworkDiskCache* cache = new QNetworkDiskCache(); - cache->moveToThread(networkAccessManager.thread()); - cache->setParent(&networkAccessManager); - cache->setCacheDirectory(!cachePath.isEmpty() ? cachePath : "interfaceCache"); networkAccessManager.setCache(cache); From 8382f764cdb9422c77066fe8b829e87ae8e7c0c6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Jul 2014 12:15:55 -0700 Subject: [PATCH 10/15] Got rid of unneccessary Q_DISABLE_COPY() --- libraries/networking/src/NetworkAccessManager.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/NetworkAccessManager.h b/libraries/networking/src/NetworkAccessManager.h index c1e22f5082..9594170518 100644 --- a/libraries/networking/src/NetworkAccessManager.h +++ b/libraries/networking/src/NetworkAccessManager.h @@ -22,7 +22,6 @@ public: private: NetworkAccessManager(); - Q_DISABLE_COPY(NetworkAccessManager) }; #endif // hifi_NetworkAccessManager_h \ No newline at end of file From df6bbd29447e66068b236d59e571e1c0c1c2db19 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Jul 2014 13:47:31 -0700 Subject: [PATCH 11/15] Fix goTo* dialog bug with chat on Mac OSX If chat was open, when pressing enter on Mac OSX the operation would not go through and would focus on the chat window. There seems to be a deeper issue, but it was decided to go with the simple solution of making these dialog windows not of `Sheet` type. --- interface/src/Menu.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 402347c5d4..c9dfa16915 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1000,7 +1000,6 @@ void Menu::goToDomainDialog() { domainDialog.setWindowTitle("Go to Domain"); domainDialog.setLabelText("Domain server:"); domainDialog.setTextValue(currentDomainHostname); - domainDialog.setWindowFlags(Qt::Sheet); domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height()); int dialogReturn = domainDialog.exec(); @@ -1038,7 +1037,6 @@ void Menu::goTo() { QString destination = QString(); gotoDialog.setTextValue(destination); - gotoDialog.setWindowFlags(Qt::Sheet); gotoDialog.resize(gotoDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, gotoDialog.size().height()); int dialogReturn = gotoDialog.exec(); @@ -1154,7 +1152,6 @@ void Menu::goToLocation() { coordinateDialog.setWindowTitle("Go to Location"); coordinateDialog.setLabelText("Coordinate as x,y,z:"); coordinateDialog.setTextValue(currentLocation); - coordinateDialog.setWindowFlags(Qt::Sheet); coordinateDialog.resize(coordinateDialog.parentWidget()->size().width() * 0.30, coordinateDialog.size().height()); int dialogReturn = coordinateDialog.exec(); @@ -1208,7 +1205,6 @@ void Menu::nameLocation() { "(wherever you are standing and looking now) as you.\n\n" "Location name:"); - nameDialog.setWindowFlags(Qt::Sheet); nameDialog.resize((int) (nameDialog.parentWidget()->size().width() * 0.30), nameDialog.size().height()); if (nameDialog.exec() == QDialog::Accepted) { From 69e7a17f476f17aab40f24abd6b98d04f288abb0 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Jul 2014 16:07:04 -0700 Subject: [PATCH 12/15] Rather than backing out when we find that the delta is too big, we can just write the whole thing and copy it over (with some mapping fiddlery) if it turns out to be too big. --- .../src/metavoxels/MetavoxelServer.cpp | 26 +++++++++---------- libraries/metavoxels/src/Bitstream.cpp | 6 +---- libraries/metavoxels/src/Bitstream.h | 10 +++---- .../metavoxels/src/DatagramSequencer.cpp | 25 +++++++++--------- libraries/metavoxels/src/DatagramSequencer.h | 3 +++ libraries/metavoxels/src/MetavoxelData.cpp | 14 ---------- libraries/metavoxels/src/MetavoxelData.h | 7 ----- tests/metavoxels/src/MetavoxelTests.cpp | 25 ++++++++---------- 8 files changed, 42 insertions(+), 74 deletions(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index a01efddbf4..28f1a423c7 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -113,33 +113,31 @@ void MetavoxelSession::update() { return; } Bitstream& out = _sequencer.startPacket(); + int start = _sequencer.getOutputStream().getUnderlying().device()->pos(); out << QVariant::fromValue(MetavoxelDeltaMessage()); PacketRecord* sendRecord = getLastAcknowledgedSendRecord(); - out.setBytesRemaining(_sequencer.getMaxPacketSize()); - try { - _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); - _sequencer.endPacket(); - - } catch (const ByteLimitExceededException& exception) { - _sequencer.cancelPacket(); - + _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + out.flush(); + int end = _sequencer.getOutputStream().getUnderlying().device()->pos(); + if (end > _sequencer.getMaxPacketSize()) { // we need to send the delta on the reliable channel _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); - _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getOutputStream()); _reliableDeltaChannel->startMessage(); - _reliableDeltaChannel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); - _server->getData().writeDelta(sendRecord->getData(), sendRecord->getLOD(), _reliableDeltaChannel->getBitstream(), _lod); - _reliableDeltaWriteMappings = _reliableDeltaChannel->getBitstream().getAndResetWriteMappings(); - _reliableDeltaChannel->getBitstream().clearPersistentMappings(); + _reliableDeltaChannel->getBuffer().write(_sequencer.getOutgoingPacketData().constData() + start, end - start); _reliableDeltaChannel->endMessage(); + _reliableDeltaWriteMappings = out.getAndResetWriteMappings(); _reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten(); _reliableDeltaData = _server->getData(); _reliableDeltaLOD = _lod; - Bitstream& out = _sequencer.startPacket(); + // go back to the beginning with the current packet and note that there's a delta pending + _sequencer.getOutputStream().getUnderlying().device()->seek(start); out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); _sequencer.endPacket(); + + } else { + _sequencer.endPacket(); } } diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 459a12dc15..bc662aa890 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -127,7 +127,6 @@ Bitstream::Bitstream(QDataStream& underlying, MetadataType metadataType, Generic _underlying(underlying), _byte(0), _position(0), - _bytesRemaining(INT_MAX), _metadataType(metadataType), _genericsMode(genericsMode), _objectStreamerStreamer(*this), @@ -194,16 +193,13 @@ Bitstream& Bitstream::read(void* data, int bits, int offset) { void Bitstream::flush() { if (_position != 0) { _underlying << _byte; - _bytesRemaining--; - _byte = 0; - _position = 0; + reset(); } } void Bitstream::reset() { _byte = 0; _position = 0; - _bytesRemaining = INT_MAX; } Bitstream::WriteMappings Bitstream::getAndResetWriteMappings() { diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 97f1b70ff0..70fde94b79 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -329,6 +329,9 @@ public: Bitstream(QDataStream& underlying, MetadataType metadataType = NO_METADATA, GenericsMode = NO_GENERICS, QObject* parent = NULL); + /// Returns a reference to the underlying data stream. + QDataStream& getUnderlying() { return _underlying; } + /// Substitutes the supplied metaobject for the given class name's default mapping. This is mostly useful for testing the /// process of mapping between different types, but may in the future be used for permanently renaming classes. void addMetaObjectSubstitution(const QByteArray& className, const QMetaObject* metaObject); @@ -355,12 +358,6 @@ public: /// Resets to the initial state. void reset(); - /// Sets the number of "bytes remaining," which will be decremented with each byte written. - void setBytesRemaining(int bytesRemaining) { _bytesRemaining = bytesRemaining; } - - /// Returns the number of bytes remaining. - int getBytesRemaining() const { return _bytesRemaining; } - /// Returns the set of transient mappings gathered during writing and resets them. WriteMappings getAndResetWriteMappings(); @@ -546,7 +543,6 @@ private: QDataStream& _underlying; quint8 _byte; int _position; - int _bytesRemaining; MetadataType _metadataType; GenericsMode _genericsMode; diff --git a/libraries/metavoxels/src/DatagramSequencer.cpp b/libraries/metavoxels/src/DatagramSequencer.cpp index 2ef3d0213c..2c594fc1ca 100644 --- a/libraries/metavoxels/src/DatagramSequencer.cpp +++ b/libraries/metavoxels/src/DatagramSequencer.cpp @@ -113,17 +113,16 @@ Bitstream& DatagramSequencer::startPacket() { _outgoingPacketStream << (quint32)record.packetNumber; } - // write the high-priority messages - _outgoingPacketStream << (quint32)_highPriorityMessages.size(); - foreach (const HighPriorityMessage& message, _highPriorityMessages) { - _outputStream << message.data; - } - // return the stream, allowing the caller to write the rest return _outputStream; } void DatagramSequencer::endPacket() { + // write the high-priority messages + _outputStream << _highPriorityMessages.size(); + foreach (const HighPriorityMessage& message, _highPriorityMessages) { + _outputStream << message.data; + } _outputStream.flush(); // if we have space remaining, send some data from our reliable channels @@ -222,22 +221,22 @@ void DatagramSequencer::receivedDatagram(const QByteArray& datagram) { _sendRecords.erase(_sendRecords.begin(), it + 1); } + // alert external parties so that they can read the middle + emit readyToRead(_inputStream); + // read and dispatch the high-priority messages - quint32 highPriorityMessageCount; - _incomingPacketStream >> highPriorityMessageCount; + int highPriorityMessageCount; + _inputStream >> highPriorityMessageCount; int newHighPriorityMessages = highPriorityMessageCount - _receivedHighPriorityMessages; - for (quint32 i = 0; i < highPriorityMessageCount; i++) { + for (int i = 0; i < highPriorityMessageCount; i++) { QVariant data; _inputStream >> data; - if ((int)i >= _receivedHighPriorityMessages) { + if (i >= _receivedHighPriorityMessages) { emit receivedHighPriorityMessage(data); } } _receivedHighPriorityMessages = highPriorityMessageCount; - // alert external parties so that they can read the middle - emit readyToRead(_inputStream); - // read the reliable data, if any quint32 reliableChannels; _incomingPacketStream >> reliableChannels; diff --git a/libraries/metavoxels/src/DatagramSequencer.h b/libraries/metavoxels/src/DatagramSequencer.h index 32f645b13c..b85916b561 100644 --- a/libraries/metavoxels/src/DatagramSequencer.h +++ b/libraries/metavoxels/src/DatagramSequencer.h @@ -84,6 +84,9 @@ public: /// Returns a reference to the stream used to write packets. Bitstream& getOutputStream() { return _outputStream; } + /// Returns a reference to the outgoing packet data. + const QByteArray& getOutgoingPacketData() const { return _outgoingPacketData; } + /// Returns the packet number of the sent packet at the specified index. int getSentPacketNumber(int index) const { return _sendRecords.at(index).packetNumber; } diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 43206588cc..2d61ede796 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -681,12 +681,6 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } -void MetavoxelStreamState::checkByteLimitExceeded() { - if (stream.getBytesRemaining() < 0) { - throw ByteLimitExceededException(); - } -} - MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) : _referenceCount(1) { @@ -778,13 +772,11 @@ void MetavoxelNode::read(MetavoxelStreamState& state) { void MetavoxelNode::write(MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { state.attribute->write(state.stream, _attributeValue, true); - state.checkByteLimitExceeded(); return; } bool leaf = isLeaf(); state.stream << leaf; state.attribute->write(state.stream, _attributeValue, leaf); - state.checkByteLimitExceeded(); if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, state.stream, state.lod, state.referenceLOD }; @@ -838,13 +830,11 @@ void MetavoxelNode::readDelta(const MetavoxelNode& reference, MetavoxelStreamSta void MetavoxelNode::writeDelta(const MetavoxelNode& reference, MetavoxelStreamState& state) const { if (!state.shouldSubdivide()) { state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, true); - state.checkByteLimitExceeded(); return; } bool leaf = isLeaf(); state.stream << leaf; state.attribute->writeDelta(state.stream, _attributeValue, reference._attributeValue, leaf); - state.checkByteLimitExceeded(); if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, state.stream, state.lod, state.referenceLOD }; @@ -907,7 +897,6 @@ void MetavoxelNode::writeSubdivision(MetavoxelStreamState& state) const { bool subdivideReference = state.shouldSubdivideReference(); if (!subdivideReference) { state.stream << leaf; - state.checkByteLimitExceeded(); } if (!leaf) { MetavoxelStreamState nextState = { glm::vec3(), state.size * 0.5f, state.attribute, @@ -932,7 +921,6 @@ void MetavoxelNode::writeSpanners(MetavoxelStreamState& state) const { foreach (const SharedObjectPointer& object, decodeInline(_attributeValue)) { if (static_cast(object.data())->testAndSetVisited()) { state.stream << object; - state.checkByteLimitExceeded(); } } if (!state.shouldSubdivide() || isLeaf()) { @@ -952,13 +940,11 @@ void MetavoxelNode::writeSpannerDelta(const MetavoxelNode& reference, MetavoxelS foreach (const SharedObjectPointer& object, oldSet) { if (static_cast(object.data())->testAndSetVisited() && !newSet.contains(object)) { state.stream << object; - state.checkByteLimitExceeded(); } } foreach (const SharedObjectPointer& object, newSet) { if (static_cast(object.data())->testAndSetVisited() && !oldSet.contains(object)) { state.stream << object; - state.checkByteLimitExceeded(); } } if (isLeaf() || !state.shouldSubdivide()) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index a0b0b6ef47..6a7ba33eb5 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -164,13 +164,6 @@ public: bool becameSubdivided() const; void setMinimum(const glm::vec3& lastMinimum, int index); - - /// Throws ByteLimitExceededException if the stream has fewer than zero bytes remaining. - void checkByteLimitExceeded(); -}; - -/// Thrown when we have exceeded the byte limit in writing. -class ByteLimitExceededException { }; /// A single node within a metavoxel layer. diff --git a/tests/metavoxels/src/MetavoxelTests.cpp b/tests/metavoxels/src/MetavoxelTests.cpp index 48ce4716b7..4132270620 100644 --- a/tests/metavoxels/src/MetavoxelTests.cpp +++ b/tests/metavoxels/src/MetavoxelTests.cpp @@ -913,33 +913,30 @@ bool TestEndpoint::simulate(int iterationNumber) { return false; } Bitstream& out = _sequencer.startPacket(); + int start = _sequencer.getOutputStream().getUnderlying().device()->pos(); out << QVariant::fromValue(MetavoxelDeltaMessage()); PacketRecord* sendRecord = getLastAcknowledgedSendRecord(); - out.setBytesRemaining(_sequencer.getMaxPacketSize()); - try { - _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); - _sequencer.endPacket(); - - } catch (const ByteLimitExceededException& exception) { - _sequencer.cancelPacket(); - + _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), out, _lod); + out.flush(); + int end = _sequencer.getOutputStream().getUnderlying().device()->pos(); + if (end > _sequencer.getMaxPacketSize()) { // we need to send the delta on the reliable channel _reliableDeltaChannel = _sequencer.getReliableOutputChannel(RELIABLE_DELTA_CHANNEL_INDEX); - _reliableDeltaChannel->getBitstream().copyPersistentMappings(_sequencer.getOutputStream()); _reliableDeltaChannel->startMessage(); - _reliableDeltaChannel->getBitstream() << QVariant::fromValue(MetavoxelDeltaMessage()); - _data.writeDelta(sendRecord->getData(), sendRecord->getLOD(), _reliableDeltaChannel->getBitstream(), _lod); - _reliableDeltaWriteMappings = _reliableDeltaChannel->getBitstream().getAndResetWriteMappings(); - _reliableDeltaChannel->getBitstream().clearPersistentMappings(); + _reliableDeltaChannel->getBuffer().write(_sequencer.getOutgoingPacketData().constData() + start, end - start); _reliableDeltaChannel->endMessage(); + _reliableDeltaWriteMappings = out.getAndResetWriteMappings(); _reliableDeltaReceivedOffset = _reliableDeltaChannel->getBytesWritten(); _reliableDeltaData = _data; _reliableDeltaLOD = _lod; - Bitstream& out = _sequencer.startPacket(); + _sequencer.getOutputStream().getUnderlying().device()->seek(start); out << QVariant::fromValue(MetavoxelDeltaPendingMessage()); _sequencer.endPacket(); + + } else { + _sequencer.endPacket(); } } else { // enqueue some number of high priority messages From 6bf4182804506262ee3ad6dcadb478ef9af9a068 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Jul 2014 16:25:13 -0700 Subject: [PATCH 13/15] Fix for send timer. --- assignment-client/src/metavoxels/MetavoxelServer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/metavoxels/MetavoxelServer.cpp b/assignment-client/src/metavoxels/MetavoxelServer.cpp index 28f1a423c7..c601478f70 100644 --- a/assignment-client/src/metavoxels/MetavoxelServer.cpp +++ b/assignment-client/src/metavoxels/MetavoxelServer.cpp @@ -21,7 +21,8 @@ const int SEND_INTERVAL = 50; MetavoxelServer::MetavoxelServer(const QByteArray& packet) : - ThreadedAssignment(packet) { + ThreadedAssignment(packet), + _sendTimer(this) { _sendTimer.setSingleShot(true); connect(&_sendTimer, SIGNAL(timeout()), SLOT(sendDeltas())); From aaae07087c4d9d9b5299834a64b737c8c17882c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Jul 2014 18:09:50 -0700 Subject: [PATCH 14/15] Fix for local edits. --- .../metavoxels/src/MetavoxelClientManager.cpp | 27 +++++++++---------- .../metavoxels/src/MetavoxelClientManager.h | 4 +-- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 9abb5e9e5d..abe54873bd 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -116,30 +116,26 @@ void MetavoxelClient::writeUpdateMessage(Bitstream& out) { out << QVariant::fromValue(state); } -void MetavoxelClient::readMessage(Bitstream& in) { - Endpoint::readMessage(in); - - // reapply local edits - foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) { - if (message.data.userType() == MetavoxelEditMessage::Type) { - message.data.value().apply(_data, _sequencer.getWeakSharedObjectHash()); - } - } -} - void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { int userType = message.userType(); if (userType == MetavoxelDeltaMessage::Type) { PacketRecord* receiveRecord = getLastAcknowledgedReceiveRecord(); if (_reliableDeltaChannel) { - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _dataLOD = _reliableDeltaLOD); + _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = _reliableDeltaLOD); _sequencer.getInputStream().persistReadMappings(in.getAndResetReadMappings()); in.clearPersistentMappings(); _reliableDeltaChannel = NULL; } else { - _data.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, - _dataLOD = getLastAcknowledgedSendRecord()->getLOD()); + _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, + _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); + } + // copy to local and reapply local edits + _data = _remoteData; + foreach (const DatagramSequencer::HighPriorityMessage& message, _sequencer.getHighPriorityMessages()) { + if (message.data.userType() == MetavoxelEditMessage::Type) { + message.data.value().apply(_data, _sequencer.getWeakSharedObjectHash()); + } } } else if (userType == MetavoxelDeltaPendingMessage::Type) { if (!_reliableDeltaChannel) { @@ -157,5 +153,6 @@ PacketRecord* MetavoxelClient::maybeCreateSendRecord() const { } PacketRecord* MetavoxelClient::maybeCreateReceiveRecord() const { - return new PacketRecord(_dataLOD, _data); + return new PacketRecord(_remoteDataLOD, _remoteData); } + diff --git a/libraries/metavoxels/src/MetavoxelClientManager.h b/libraries/metavoxels/src/MetavoxelClientManager.h index 9ab2e2c8b0..1f37b15c18 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.h +++ b/libraries/metavoxels/src/MetavoxelClientManager.h @@ -60,7 +60,6 @@ public: protected: virtual void writeUpdateMessage(Bitstream& out); - virtual void readMessage(Bitstream& in); virtual void handleMessage(const QVariant& message, Bitstream& in); virtual PacketRecord* maybeCreateSendRecord() const; @@ -70,7 +69,8 @@ private: MetavoxelClientManager* _manager; MetavoxelData _data; - MetavoxelLOD _dataLOD; + MetavoxelData _remoteData; + MetavoxelLOD _remoteDataLOD; ReliableChannel* _reliableDeltaChannel; MetavoxelLOD _reliableDeltaLOD; From 365bc2a93e005a4f1d1ce46702cb77b46ff3e081 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 7 Jul 2014 19:27:04 -0700 Subject: [PATCH 15/15] Need to reset the stream here. --- libraries/metavoxels/src/MetavoxelClientManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index abe54873bd..e69794917f 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -129,6 +129,7 @@ void MetavoxelClient::handleMessage(const QVariant& message, Bitstream& in) { } else { _remoteData.readDelta(receiveRecord->getData(), receiveRecord->getLOD(), in, _remoteDataLOD = getLastAcknowledgedSendRecord()->getLOD()); + in.reset(); } // copy to local and reapply local edits _data = _remoteData;