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.
This commit is contained in:
Andrzej Kapolka 2014-07-07 16:07:04 -07:00
parent 44befbb019
commit 69e7a17f47
8 changed files with 42 additions and 74 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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<SharedObjectSet>(_attributeValue)) {
if (static_cast<Spanner*>(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<Spanner*>(object.data())->testAndSetVisited() && !newSet.contains(object)) {
state.stream << object;
state.checkByteLimitExceeded();
}
}
foreach (const SharedObjectPointer& object, newSet) {
if (static_cast<Spanner*>(object.data())->testAndSetVisited() && !oldSet.contains(object)) {
state.stream << object;
state.checkByteLimitExceeded();
}
}
if (isLeaf() || !state.shouldSubdivide()) {

View file

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

View file

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