From 24b2da1c0de3c8214a0340de947e47833ad18afb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 18 Mar 2014 13:14:21 -0700 Subject: [PATCH] Working on delta streaming. --- libraries/metavoxels/src/Bitstream.cpp | 19 ++++++++++++ libraries/metavoxels/src/Bitstream.h | 37 ++++++++++++++++++++++- libraries/metavoxels/src/SharedObject.cpp | 10 +++++- libraries/metavoxels/src/SharedObject.h | 5 ++- tools/mtc/src/main.cpp | 20 ++++++++++++ 5 files changed, 88 insertions(+), 3 deletions(-) diff --git a/libraries/metavoxels/src/Bitstream.cpp b/libraries/metavoxels/src/Bitstream.cpp index 0708ede5b6..6bad482ca1 100644 --- a/libraries/metavoxels/src/Bitstream.cpp +++ b/libraries/metavoxels/src/Bitstream.cpp @@ -865,6 +865,21 @@ QVariant TypeReader::read(Bitstream& in) const { return object; } +void TypeReader::readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const { + if (_exactMatch) { + _streamer->readDelta(in, object, reference); + return; + } + if (_valueReader) { + // TODO: collection deltas + + } else { + foreach (const FieldReader& field, _fields) { + field.readDelta(in, _streamer, object, reference); + } + } +} + bool TypeReader::matchesExactly(const TypeStreamer* streamer) const { return _exactMatch && _streamer == streamer; } @@ -885,6 +900,10 @@ void FieldReader::read(Bitstream& in, const TypeStreamer* streamer, QVariant& ob } } +void FieldReader::readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const { + // TODO: field delta +} + ObjectReader::ObjectReader(const QByteArray& className, const QMetaObject* metaObject, const QVector& properties) : _className(className), diff --git a/libraries/metavoxels/src/Bitstream.h b/libraries/metavoxels/src/Bitstream.h index 769ae4a250..cd885d9f81 100644 --- a/libraries/metavoxels/src/Bitstream.h +++ b/libraries/metavoxels/src/Bitstream.h @@ -268,6 +268,9 @@ public: /// Removes a shared object from the read mappings. void clearSharedObject(int id); + template void writeDelta(const T& value, const T& reference); + template void readDelta(T& value, const T& reference); + Bitstream& operator<<(bool value); Bitstream& operator>>(bool& value); @@ -378,6 +381,23 @@ private: static QVector getPropertyReaders(const QMetaObject* metaObject); }; +template inline void Bitstream::writeDelta(const T& value, const T& reference) { + if (value == reference) { + *this << false; + } else { + *this << true; + *this << value; + } +} + +template inline void Bitstream::readDelta(T& value, const T& reference) { + bool changed; + *this >> changed; + if (changed) { + *this >> value; + } +} + template inline Bitstream& Bitstream::operator<<(const QList& list) { *this << list.size(); foreach (const T& entry, list) { @@ -458,6 +478,7 @@ public: const TypeStreamer* getStreamer() const { return _streamer; } QVariant read(Bitstream& in) const; + void readDelta(Bitstream& in, QVariant& object, const QVariant& reference) const; bool matchesExactly(const TypeStreamer* streamer) const; @@ -486,7 +507,8 @@ public: int getIndex() const { return _index; } void read(Bitstream& in, const TypeStreamer* streamer, QVariant& object) const; - + void readDelta(Bitstream& in, const TypeStreamer* streamer, QVariant& object, const QVariant& reference) const; + private: TypeReader _reader; @@ -565,6 +587,9 @@ public: virtual void write(Bitstream& out, const QVariant& value) const = 0; virtual QVariant read(Bitstream& in) const = 0; + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const = 0; + virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const = 0; + virtual const QVector& getMetaFields() const; virtual int getFieldIndex(const QByteArray& name) const; virtual void setField(int index, QVariant& object, const QVariant& value) const; @@ -590,6 +615,10 @@ public: virtual void write(Bitstream& out, const QVariant& value) const { out << value.value(); } virtual QVariant read(Bitstream& in) const { T value; in >> value; return QVariant::fromValue(value); } + virtual void writeDelta(Bitstream& out, const QVariant& value, const QVariant& reference) const { + out.writeDelta(value.value(), reference.value()); } + virtual void readDelta(Bitstream& in, QVariant& value, const QVariant& reference) const { + in.readDelta(*static_cast(value.data()), reference.value()); } }; /// A streamer for types compiled by mtc. @@ -652,6 +681,8 @@ public: #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ Bitstream& operator<<(Bitstream& out, const X& obj); \ Bitstream& operator>>(Bitstream& in, X& obj); \ + template<> void Bitstream::writeDelta(const X& value, const X& reference); \ + template<> void Bitstream::readDelta(X& value, const X& reference); \ bool operator==(const X& first, const X& second); \ bool operator!=(const X& first, const X& second); \ static const int* _TypePtr##X = &X::Type; @@ -659,6 +690,8 @@ public: #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ Bitstream& operator<<(Bitstream& out, const X& obj); \ Bitstream& operator>>(Bitstream& in, X& obj); \ + template<> void Bitstream::writeDelta(const X& value, const X& reference); \ + template<> void Bitstream::readDelta(X& value, const X& reference); \ bool operator==(const X& first, const X& second); \ bool operator!=(const X& first, const X& second); \ __attribute__((unused)) static const int* _TypePtr##X = &X::Type; @@ -667,6 +700,8 @@ public: #define DECLARE_STREAMABLE_METATYPE(X) Q_DECLARE_METATYPE(X) \ Bitstream& operator<<(Bitstream& out, const X& obj); \ Bitstream& operator>>(Bitstream& in, X& obj); \ + template<> void Bitstream::writeDelta(const X& value, const X& reference); \ + template<> void Bitstream::readDelta(X& value, const X& reference); \ bool operator==(const X& first, const X& second); \ bool operator!=(const X& first, const X& second); \ static const int* _TypePtr##X = &X::Type; \ diff --git a/libraries/metavoxels/src/SharedObject.cpp b/libraries/metavoxels/src/SharedObject.cpp index e95958ac76..36257a740f 100644 --- a/libraries/metavoxels/src/SharedObject.cpp +++ b/libraries/metavoxels/src/SharedObject.cpp @@ -37,7 +37,7 @@ void SharedObject::decrementReferenceCount() { } } -SharedObject* SharedObject::clone() const { +SharedObject* SharedObject::clone(bool withID) const { // default behavior is to make a copy using the no-arg constructor and copy the stored properties const QMetaObject* metaObject = this->metaObject(); SharedObject* newObject = static_cast(metaObject->newInstance()); @@ -50,6 +50,9 @@ SharedObject* SharedObject::clone() const { foreach (const QByteArray& propertyName, dynamicPropertyNames()) { newObject->setProperty(propertyName, property(propertyName)); } + if (withID) { + newObject->setID(_id); + } return newObject; } @@ -91,6 +94,11 @@ void SharedObject::dump(QDebug debug) const { } } +void SharedObject::setID(int id) { + _weakHash.remove(_id); + _weakHash.insert(_id = id, this); +} + int SharedObject::_lastID = 0; WeakSharedObjectHash SharedObject::_weakHash; diff --git a/libraries/metavoxels/src/SharedObject.h b/libraries/metavoxels/src/SharedObject.h index 66e6474972..435127fffd 100644 --- a/libraries/metavoxels/src/SharedObject.h +++ b/libraries/metavoxels/src/SharedObject.h @@ -47,7 +47,8 @@ public: void decrementReferenceCount(); /// Creates a new clone of this object. - virtual SharedObject* clone() const; + /// \param withID if true, give the clone the same ID as this object + virtual SharedObject* clone(bool withID = false) const; /// Tests this object for equality with another. virtual bool equals(const SharedObject* other) const; @@ -57,6 +58,8 @@ public: private: + void setID(int id); + int _id; int _remoteID; int _referenceCount; diff --git a/tools/mtc/src/main.cpp b/tools/mtc/src/main.cpp index 7a546ab529..e6f1827870 100644 --- a/tools/mtc/src/main.cpp +++ b/tools/mtc/src/main.cpp @@ -172,6 +172,26 @@ void generateOutput (QTextStream& out, const QList& streamables) { out << " return in;\n"; out << "}\n"; + out << "template<> void Bitstream::writeDelta(const " << name << "& value, const " << name << "& reference) {\n"; + foreach (const QString& base, str.clazz.bases) { + out << " writeDelta(static_cast(value), static_cast(reference));\n"; + } + foreach (const Field& field, str.fields) { + out << " writeDelta(value." << field.name << ", reference." << field.name << ");\n"; + } + out << "}\n"; + + out << "template<> void Bitstream::readDelta(" << name << "& value, const " << name << "& reference) {\n"; + foreach (const QString& base, str.clazz.bases) { + out << " readDelta(static_cast<" << base << "&>(value), static_cast(reference));\n"; + } + foreach (const Field& field, str.fields) { + out << " readDelta(value." << field.name << ", reference." << field.name << ");\n"; + } + out << "}\n"; + out << "bool operator==(const " << name << "& first, const " << name << "& second) {\n"; if (str.clazz.bases.isEmpty() && str.fields.isEmpty()) { out << " return true";