diff --git a/renderdoc/api/replay/structured_data.h b/renderdoc/api/replay/structured_data.h index 17ee7cf4c..25af4b446 100644 --- a/renderdoc/api/replay/structured_data.h +++ b/renderdoc/api/replay/structured_data.h @@ -375,6 +375,10 @@ private: friend void DoSerialise(SerialiserType &ser, SDObjectData &el); template friend void DoSerialise(SerialiserType &ser, SDObject *el); + template + friend void DoSerialise(SerialiserType &ser, SDObject &el); + template + friend void DoSerialise(SerialiserType &ser, SDChunk &el); DOCUMENT("A list of :class:`SDObject` containing the children of this :class:`SDObject`."); mutable StructuredObjectList children; @@ -932,6 +936,8 @@ private: friend void DoSerialise(SerialiserType &ser, SDObject &el); template friend void DoSerialise(SerialiserType &ser, SDChunk &el); + template + friend void DoSerialise(SerialiserType &ser, SDObject &el, StructuredObjectList &children); void DeleteLazyGenerator() const { diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index 55be7c4e5..56767843d 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -686,53 +686,53 @@ void DoSerialise(SerialiserType &ser, SDObjectPODData &el) SERIALISE_MEMBER(u); } -template -void DoSerialise(SerialiserType &ser, StructuredObjectList &el) -{ - // since structured objects aren't intended to be exported as nice structured data, only for pure - // transfer purposes, we don't make a proper array here and instead just manually serialise count - // + elements - uint64_t count = el.size(); - ser.Serialise("count"_lit, count); - - if(ser.IsReading()) - el.resize((size_t)count); - - for(size_t c = 0; c < (size_t)count; c++) - { - // we also assume that the caller serialising these objects will handle lifetime management. - if(ser.IsReading()) - el[c] = new SDObject(""_lit, ""_lit); - - ser.Serialise("$el"_lit, *el[c]); - } -} - template void DoSerialise(SerialiserType &ser, SDObjectData &el) { SERIALISE_MEMBER(basic); SERIALISE_MEMBER(str); - SERIALISE_MEMBER(children); + + // this is deliberately not serialised here, it's serialised in the parent SDObject. See below + // SERIALISE_MEMBER(children); +} + +template +void DoSerialise(SerialiserType &ser, SDObject &el, StructuredObjectList &children) +{ + // serialising the data above doesn't serialise the children, so we can do it here using a + // potential lazy generator. This is so that we don't incur the full cost of populating lazy + // children all at once (which could be slow). This is a bit of a hack as this can take many + // seconds and cause a timeout during transfer, and it would be uglier to try and keep the + // connection alive while serialising chunks. + uint64_t childCount = children.size(); + SERIALISE_ELEMENT(childCount).Hidden(); + + if(ser.IsReading()) + children.resize((size_t)childCount); + + for(size_t c = 0; c < el.NumChildren(); c++) + { + // we also assume that the caller serialising these objects will handle lifetime management. + if(ser.IsReading()) + children[c] = new SDObject(""_lit, ""_lit); + else + el.PopulateChild(c); + + ser.Serialise("$el"_lit, *children[c]); + + if(ser.IsReading()) + children[c]->m_Parent = ⪙ + } } template void DoSerialise(SerialiserType &ser, SDObject &el) { - if(ser.IsWriting()) - { - el.PopulateAllChildren(); - } - SERIALISE_MEMBER(name); SERIALISE_MEMBER(type); SERIALISE_MEMBER(data); - if(ser.IsReading()) - { - for(size_t i = 0; i < el.NumChildren(); i++) - el.GetChild(i)->m_Parent = ⪙ - } + DoSerialise(ser, el, el.data.children); } template @@ -740,14 +740,10 @@ void DoSerialise(SerialiserType &ser, SDChunk &el) { SERIALISE_MEMBER(name); SERIALISE_MEMBER(type); - SERIALISE_MEMBER(data); SERIALISE_MEMBER(metadata); + SERIALISE_MEMBER(data); - if(ser.IsReading()) - { - for(size_t i = 0; i < el.NumChildren(); i++) - el.GetChild(i)->m_Parent = ⪙ - } + DoSerialise(ser, el, el.data.children); } INSTANTIATE_SERIALISE_TYPE(SDChunk);