Working on metavoxel streaming tests.

This commit is contained in:
Andrzej Kapolka 2014-06-19 18:15:17 -07:00
parent 7a9c0f0e6a
commit 24f535e02d
3 changed files with 196 additions and 54 deletions

View file

@ -687,6 +687,23 @@ MetavoxelNode* MetavoxelData::createRoot(const AttributePointer& attribute) {
return root = new MetavoxelNode(attribute); return root = new MetavoxelNode(attribute);
} }
bool MetavoxelData::deepEquals(const MetavoxelData& other, const MetavoxelLOD& lod) const {
if (_size != other._size) {
return false;
}
if (_roots.size() != other._roots.size()) {
return false;
}
glm::vec3 minimum = getMinimum();
for (QHash<AttributePointer, MetavoxelNode*>::const_iterator it = _roots.constBegin(); it != _roots.constEnd(); it++) {
MetavoxelNode* otherNode = other._roots.value(it.key());
if (!(otherNode && it.value()->deepEquals(it.key(), *otherNode, minimum, _size, lod))) {
return false;
}
}
return true;
}
bool MetavoxelData::operator==(const MetavoxelData& other) const { bool MetavoxelData::operator==(const MetavoxelData& other) const {
return _size == other._size && _roots == other._roots; return _size == other._size && _roots == other._roots;
} }
@ -1083,6 +1100,31 @@ void MetavoxelNode::clearChildren(const AttributePointer& attribute) {
} }
} }
bool MetavoxelNode::deepEquals(const AttributePointer& attribute, const MetavoxelNode& other,
const glm::vec3& minimum, float size, const MetavoxelLOD& lod) const {
if (!attribute->equal(_attributeValue, other._attributeValue)) {
return false;
}
if (!lod.shouldSubdivide(minimum, size, attribute->getLODThresholdMultiplier())) {
return true;
}
bool leaf = isLeaf(), otherLeaf = other.isLeaf();
if (leaf && otherLeaf) {
return true;
}
if (leaf || otherLeaf) {
return false;
}
float nextSize = size * 0.5f;
for (int i = 0; i < CHILD_COUNT; i++) {
glm::vec3 nextMinimum = getNextMinimum(minimum, nextSize, i);
if (!_children[i]->deepEquals(attribute, *(other._children[i]), nextMinimum, nextSize, lod)) {
return false;
}
}
return true;
}
int MetavoxelVisitor::encodeOrder(int first, int second, int third, int fourth, int MetavoxelVisitor::encodeOrder(int first, int second, int third, int fourth,
int fifth, int sixth, int seventh, int eighth) { int fifth, int sixth, int seventh, int eighth) {
return first | (second << 3) | (third << 6) | (fourth << 9) | return first | (second << 3) | (third << 6) | (fourth << 9) |
@ -1111,6 +1153,10 @@ int MetavoxelVisitor::encodeOrder(const glm::vec3& direction) {
indexDistances.at(6).index, indexDistances.at(7).index); indexDistances.at(6).index, indexDistances.at(7).index);
} }
int MetavoxelVisitor::encodeRandomOrder() {
return DEFAULT_ORDER;
}
const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7); const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7);
const int MetavoxelVisitor::STOP_RECURSION = 0; const int MetavoxelVisitor::STOP_RECURSION = 0;
const int MetavoxelVisitor::SHORT_CIRCUIT = -1; const int MetavoxelVisitor::SHORT_CIRCUIT = -1;

View file

@ -126,6 +126,10 @@ public:
MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); } MetavoxelNode* getRoot(const AttributePointer& attribute) const { return _roots.value(attribute); }
MetavoxelNode* createRoot(const AttributePointer& attribute); MetavoxelNode* createRoot(const AttributePointer& attribute);
/// Performs a deep comparison between this data and the specified other (as opposed to the == operator, which does a
/// shallow comparison).
bool deepEquals(const MetavoxelData& other, const MetavoxelLOD& lod = MetavoxelLOD()) const;
bool operator==(const MetavoxelData& other) const; bool operator==(const MetavoxelData& other) const;
bool operator!=(const MetavoxelData& other) const; bool operator!=(const MetavoxelData& other) const;
@ -214,6 +218,10 @@ public:
void clearChildren(const AttributePointer& attribute); void clearChildren(const AttributePointer& attribute);
/// Performs a deep comparison between this and the specified other node.
bool deepEquals(const AttributePointer& attribute, const MetavoxelNode& other,
const glm::vec3& minimum, float size, const MetavoxelLOD& lod) const;
private: private:
Q_DISABLE_COPY(MetavoxelNode) Q_DISABLE_COPY(MetavoxelNode)
@ -250,6 +258,9 @@ public:
/// Encodes a visitation order sequence that visits each child as sorted along the specified direction. /// Encodes a visitation order sequence that visits each child as sorted along the specified direction.
static int encodeOrder(const glm::vec3& direction); static int encodeOrder(const glm::vec3& direction);
/// Returns a random visitation order sequence.
static int encodeRandomOrder();
/// The default visitation order. /// The default visitation order.
static const int DEFAULT_ORDER; static const int DEFAULT_ORDER;

View file

@ -32,6 +32,8 @@ static int datagramsSent = 0;
static int datagramsReceived = 0; static int datagramsReceived = 0;
static int bytesSent = 0; static int bytesSent = 0;
static int bytesReceived = 0; static int bytesReceived = 0;
static int maxDatagramsPerPacket = 0;
static int maxBytesPerPacket = 0;
static int highPriorityMessagesSent = 0; static int highPriorityMessagesSent = 0;
static int highPriorityMessagesReceived = 0; static int highPriorityMessagesReceived = 0;
static int unreliableMessagesSent = 0; static int unreliableMessagesSent = 0;
@ -353,6 +355,7 @@ bool MetavoxelTests::run() {
qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived; qDebug() << "Sent" << streamedBytesSent << "streamed bytes, received" << streamedBytesReceived;
qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" <<
datagramsReceived << "with" << bytesReceived << "bytes"; datagramsReceived << "with" << bytesReceived << "bytes";
qDebug() << "Max" << maxDatagramsPerPacket << "datagrams," << maxBytesPerPacket << "bytes per packet";
qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed; qDebug() << "Created" << sharedObjectsCreated << "shared objects, destroyed" << sharedObjectsDestroyed;
qDebug() << "Performed" << objectMutationsPerformed << "object mutations"; qDebug() << "Performed" << objectMutationsPerformed << "object mutations";
qDebug() << "Created" << scriptObjectsCreated << "script objects, mutated" << scriptMutationsPerformed; qDebug() << "Created" << scriptObjectsCreated << "script objects, mutated" << scriptMutationsPerformed;
@ -373,7 +376,7 @@ bool MetavoxelTests::run() {
qDebug(); qDebug();
// clear the stats // clear the stats
datagramsSent = bytesSent = datagramsReceived = bytesReceived = 0; datagramsSent = bytesSent = datagramsReceived = bytesReceived = maxDatagramsPerPacket = maxBytesPerPacket = 0;
// create client and server endpoints // create client and server endpoints
Endpoint client(datagramHeader, Endpoint::METAVOXEL_CLIENT_MODE); Endpoint client(datagramHeader, Endpoint::METAVOXEL_CLIENT_MODE);
@ -391,6 +394,7 @@ bool MetavoxelTests::run() {
qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" << qDebug() << "Sent" << datagramsSent << "datagrams with" << bytesSent << "bytes, received" <<
datagramsReceived << "with" << bytesReceived << "bytes"; datagramsReceived << "with" << bytesReceived << "bytes";
qDebug() << "Max" << maxDatagramsPerPacket << "datagrams," << maxBytesPerPacket << "bytes per packet";
} }
qDebug() << "All tests passed!"; qDebug() << "All tests passed!";
@ -407,6 +411,34 @@ static SharedObjectPointer createRandomSharedObject() {
} }
} }
class RandomVisitor : public MetavoxelVisitor {
public:
int leafCount;
RandomVisitor();
virtual int visit(MetavoxelInfo& info);
};
RandomVisitor::RandomVisitor() :
MetavoxelVisitor(QVector<AttributePointer>(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute()),
leafCount(0) {
}
const float MAXIMUM_LEAF_SIZE = 0.5f;
const float MINIMUM_LEAF_SIZE = 0.25f;
int RandomVisitor::visit(MetavoxelInfo& info) {
if (info.size > MAXIMUM_LEAF_SIZE || (info.size > MINIMUM_LEAF_SIZE && randomBoolean())) {
return DEFAULT_ORDER;
}
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<QRgb>(qRgb(randIntInRange(0, 255),
randIntInRange(0, 255), randIntInRange(0, 255))));
leafCount++;
return STOP_RECURSION;
}
Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) : Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) :
_mode(mode), _mode(mode),
_sequencer(new DatagramSequencer(datagramHeader, this)), _sequencer(new DatagramSequencer(datagramHeader, this)),
@ -434,6 +466,12 @@ Endpoint::Endpoint(const QByteArray& datagramHeader, Mode mode) :
return; return;
} }
if (mode == METAVOXEL_SERVER_MODE) { if (mode == METAVOXEL_SERVER_MODE) {
_data.expand();
_data.expand();
RandomVisitor visitor;
_data.guide(visitor);
qDebug() << "Created" << visitor.leafCount << "base leaves";
return; return;
} }
// create the object that represents out delta-encoded state // create the object that represents out delta-encoded state
@ -552,6 +590,36 @@ static bool messagesEqual(const QVariant& firstMessage, const QVariant& secondMe
} }
} }
class MutateVisitor : public MetavoxelVisitor {
public:
MutateVisitor();
virtual int visit(MetavoxelInfo& info);
private:
bool _finished;
};
MutateVisitor::MutateVisitor() :
MetavoxelVisitor(QVector<AttributePointer>(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getColorAttribute()),
_finished(false) {
}
int MutateVisitor::visit(MetavoxelInfo& info) {
if (_finished) {
return STOP_RECURSION;
}
if (info.size > MAXIMUM_LEAF_SIZE || (info.size > MINIMUM_LEAF_SIZE && randomBoolean())) {
return encodeRandomOrder();
}
info.outputValues[0] = OwnedAttributeValue(_outputs.at(0), encodeInline<QRgb>(qRgb(randIntInRange(0, 255),
randIntInRange(0, 255), randIntInRange(0, 255))));
_finished = true;
return STOP_RECURSION;
}
bool Endpoint::simulate(int iterationNumber) { bool Endpoint::simulate(int iterationNumber) {
// update/send our delayed datagrams // update/send our delayed datagrams
for (QList<QPair<QByteArray, int> >::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) { for (QList<QPair<QByteArray, int> >::iterator it = _delayedDatagrams.begin(); it != _delayedDatagrams.end(); ) {
@ -565,6 +633,8 @@ bool Endpoint::simulate(int iterationNumber) {
} }
} }
int oldDatagramsSent = datagramsSent;
int oldBytesSent = bytesSent;
if (_mode == METAVOXEL_CLIENT_MODE) { if (_mode == METAVOXEL_CLIENT_MODE) {
Bitstream& out = _sequencer->startPacket(); Bitstream& out = _sequencer->startPacket();
@ -575,69 +645,74 @@ bool Endpoint::simulate(int iterationNumber) {
// record the send // record the send
SendRecord record = { _sequencer->getOutgoingPacketNumber(), SharedObjectPointer(), MetavoxelData(), _lod }; SendRecord record = { _sequencer->getOutgoingPacketNumber(), SharedObjectPointer(), MetavoxelData(), _lod };
_sendRecords.append(record); _sendRecords.append(record);
return false;
} } else if (_mode == METAVOXEL_SERVER_MODE) {
if (_mode == METAVOXEL_SERVER_MODE) { // make a random change
// wait until we have a valid lod MutateVisitor visitor;
_data.guide(visitor);
// wait until we have a valid lod before sending
if (!_lod.isValid()) { if (!_lod.isValid()) {
return false; return false;
} }
Bitstream& out = _sequencer->startPacket(); Bitstream& out = _sequencer->startPacket();
out << QVariant::fromValue(MetavoxelDeltaMessage()); out << QVariant::fromValue(MetavoxelDeltaMessage());
_data.writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod); _data.writeDelta(_sendRecords.first().data, _sendRecords.first().lod, out, _lod);
_sequencer->endPacket();
// record the send // record the send
SendRecord record = { _sequencer->getOutgoingPacketNumber(), SharedObjectPointer(), _data, _lod }; SendRecord record = { _sequencer->getOutgoingPacketNumber() + 1, SharedObjectPointer(), _data, _lod };
_sendRecords.append(record); _sendRecords.append(record);
return false;
}
// enqueue some number of high priority messages
const float MIN_HIGH_PRIORITY_MESSAGES = 0.0f;
const float MAX_HIGH_PRIORITY_MESSAGES = 2.0f;
_highPriorityMessagesToSend += randFloatInRange(MIN_HIGH_PRIORITY_MESSAGES, MAX_HIGH_PRIORITY_MESSAGES);
while (_highPriorityMessagesToSend >= 1.0f) {
QVariant message = createRandomMessage();
_highPriorityMessagesSent.append(message);
_sequencer->sendHighPriorityMessage(message);
highPriorityMessagesSent++;
_highPriorityMessagesToSend -= 1.0f;
}
// and some number of reliable messages
const float MIN_RELIABLE_MESSAGES = 0.0f;
const float MAX_RELIABLE_MESSAGES = 4.0f;
_reliableMessagesToSend += randFloatInRange(MIN_RELIABLE_MESSAGES, MAX_RELIABLE_MESSAGES);
while (_reliableMessagesToSend >= 1.0f) {
QVariant message = createRandomMessage();
_reliableMessagesSent.append(message);
_sequencer->getReliableOutputChannel()->sendMessage(message);
reliableMessagesSent++;
_reliableMessagesToSend -= 1.0f;
}
// tweak the local state
_localState = mutate(_localState);
// send a packet
try {
Bitstream& out = _sequencer->startPacket();
SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState };
_unreliableMessagesSent.append(message);
unreliableMessagesSent++;
out << message;
_sequencer->endPacket(); _sequencer->endPacket();
} else {
// enqueue some number of high priority messages
const float MIN_HIGH_PRIORITY_MESSAGES = 0.0f;
const float MAX_HIGH_PRIORITY_MESSAGES = 2.0f;
_highPriorityMessagesToSend += randFloatInRange(MIN_HIGH_PRIORITY_MESSAGES, MAX_HIGH_PRIORITY_MESSAGES);
while (_highPriorityMessagesToSend >= 1.0f) {
QVariant message = createRandomMessage();
_highPriorityMessagesSent.append(message);
_sequencer->sendHighPriorityMessage(message);
highPriorityMessagesSent++;
_highPriorityMessagesToSend -= 1.0f;
}
// and some number of reliable messages
const float MIN_RELIABLE_MESSAGES = 0.0f;
const float MAX_RELIABLE_MESSAGES = 4.0f;
_reliableMessagesToSend += randFloatInRange(MIN_RELIABLE_MESSAGES, MAX_RELIABLE_MESSAGES);
while (_reliableMessagesToSend >= 1.0f) {
QVariant message = createRandomMessage();
_reliableMessagesSent.append(message);
_sequencer->getReliableOutputChannel()->sendMessage(message);
reliableMessagesSent++;
_reliableMessagesToSend -= 1.0f;
}
// tweak the local state
_localState = mutate(_localState);
// send a packet
try {
Bitstream& out = _sequencer->startPacket();
SequencedTestMessage message = { iterationNumber, createRandomMessage(), _localState };
_unreliableMessagesSent.append(message);
unreliableMessagesSent++;
out << message;
_sequencer->endPacket();
} catch (const QString& message) {
qDebug() << message;
return true;
}
} catch (const QString& message) { // record the send
qDebug() << message; SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState };
return true; _sendRecords.append(record);
} }
maxDatagramsPerPacket = qMax(maxDatagramsPerPacket, datagramsSent - oldDatagramsSent);
// record the send maxBytesPerPacket = qMax(maxBytesPerPacket, bytesSent - oldBytesSent);
SendRecord record = { _sequencer->getOutgoingPacketNumber(), _localState };
_sendRecords.append(record);
return false; return false;
} }
@ -692,9 +767,19 @@ void Endpoint::readMessage(Bitstream& in) {
in >> message; in >> message;
handleMessage(message, in); handleMessage(message, in);
// deep-compare data to sent version
int packetNumber = _sequencer->getIncomingPacketNumber();
foreach (const SendRecord& sendRecord, _other->_sendRecords) {
if (sendRecord.packetNumber == packetNumber) {
if (!sendRecord.data.deepEquals(_data, _sendRecords.first().lod)) {
throw QString("Sent/received metavoxel data mismatch.");
}
break;
}
}
// record the receipt // record the receipt
ReceiveRecord record = { _sequencer->getIncomingPacketNumber(), SharedObjectPointer(), ReceiveRecord record = { packetNumber, SharedObjectPointer(), _data, _sendRecords.first().lod };
_data, _sendRecords.first().lod };
_receiveRecords.append(record); _receiveRecords.append(record);
return; return;
} }