From 14bc99947c6327737837a3006fba4668e2fd8729 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 29 Oct 2019 16:42:48 +0000 Subject: [PATCH] Add a debug-only mode to log everything going through a serialiser * We also allow structured export on write, again in debug builds only --- renderdoc/serialise/serialiser.cpp | 96 +++++++++++++++++++++++++++++- renderdoc/serialise/serialiser.h | 26 ++++++-- 2 files changed, 115 insertions(+), 7 deletions(-) diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index baae33d88..10caa9c35 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -29,11 +29,58 @@ #include "core/core.h" #include "strings/string_utils.h" -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) int64_t Chunk::m_LiveChunks = 0; int64_t Chunk::m_TotalMem = 0; +void DumpObject(FileIO::LogFileHandle *log, const rdcstr &indent, SDObject *obj) +{ + if(obj->NumChildren() > 0) + { + std::string msg = + StringFormat::Fmt("%s%s%s %s:\n", indent.c_str(), obj->type.name.c_str(), + obj->type.basetype == SDBasic::Array ? "[]" : "", obj->name.c_str()); + FileIO::logfile_append(log, msg.c_str(), msg.size()); + for(size_t i = 0; i < obj->NumChildren(); i++) + DumpObject(log, indent + " ", obj->GetChild(i)); + } + else + { + rdcstr val; + switch(obj->type.basetype) + { + case SDBasic::Chunk: val = "{Chunk}"; break; + case SDBasic::Struct: val = "{Struct}"; break; + case SDBasic::Array: + // this must be an empty array, or it would have children above + val = "{}"; + break; + case SDBasic::Buffer: val = "[buffer]"; break; + case SDBasic::Null: val = "NULL"; break; + case SDBasic::String: val = obj->data.str; break; + case SDBasic::Enum: val = obj->data.str; break; + case SDBasic::UnsignedInteger: val = ToStr(obj->data.basic.u); break; + case SDBasic::SignedInteger: val = ToStr(obj->data.basic.i); break; + case SDBasic::Float: val = ToStr(obj->data.basic.d); break; + case SDBasic::Boolean: val = ToStr(obj->data.basic.b); break; + case SDBasic::Character: val = ToStr(obj->data.basic.c); break; + case SDBasic::Resource: val = ToStr(obj->data.basic.id); break; + } + std::string msg = StringFormat::Fmt("%s%s %s = %s\n", indent.c_str(), obj->type.name.c_str(), + obj->name.c_str(), val.c_str()); + FileIO::logfile_append(log, msg.c_str(), msg.size()); + } +} + +void DumpChunk(bool reading, FileIO::LogFileHandle *log, SDChunk *chunk) +{ + std::string msg = StringFormat::Fmt("%s %s @ %llu:\n", reading ? "Read" : "Wrote", + chunk->name.c_str(), chunk->metadata.timestampMicro); + FileIO::logfile_append(log, msg.c_str(), msg.size()); + DumpObject(log, " ", chunk); +} + #endif ///////////////////////////////////////////////////////////// @@ -217,6 +264,13 @@ void Serialiser::EndChunk() m_StructureStack.back()->type.byteSize = m_ChunkMetadata.length; m_StructureStack.pop_back(); } + +#if ENABLED(RDOC_DEVEL) + if(m_DebugDumpLog && !m_StructuredFile->chunks.empty()) + { + DumpChunk(true, m_DebugDumpLog, m_StructuredFile->chunks.back()); + } +#endif } // only skip remaining bytes if we have a valid length - if we have a length of 0 we wrote this @@ -379,6 +433,22 @@ uint32_t Serialiser::BeginChunk(uint32_t chunkID, uint6 } } + if(ExportStructure()) + { + std::string name = m_ChunkLookup ? m_ChunkLookup(chunkID) : ""; + + if(name.empty()) + name = ""; + + SDChunk *chunk = new SDChunk(name.c_str()); + chunk->metadata = m_ChunkMetadata; + + m_StructuredFile->chunks.push_back(chunk); + m_StructureStack.push_back(chunk); + + m_InternalElement = false; + } + return chunkID; } @@ -409,6 +479,8 @@ void Serialiser::EndChunk() } m_Write->WriteAt(chunkOffset, uint32_t(chunkLength & 0xffffffff)); + + m_ChunkMetadata.length = chunkLength; } else { @@ -443,6 +515,25 @@ void Serialiser::EndChunk() } } + if(ExportStructure()) + { + RDCASSERTMSG("Object Stack is imbalanced!", m_StructureStack.size() <= 1, + m_StructureStack.size()); + + if(!m_StructureStack.empty()) + { + m_StructureStack.back()->type.byteSize = m_ChunkMetadata.length; + m_StructureStack.pop_back(); + } + +#if ENABLED(RDOC_DEVEL) + if(m_DebugDumpLog && !m_StructuredFile->chunks.empty()) + { + DumpChunk(false, m_DebugDumpLog, m_StructuredFile->chunks.back()); + } +#endif + } + // align to the natural chunk alignment m_Write->AlignTo(); @@ -562,6 +653,8 @@ rdcstr DoStringise(const SDTypeFlags &el) STRINGISE_BITFIELD_CLASS_BIT(Hidden); STRINGISE_BITFIELD_CLASS_BIT(Nullable); STRINGISE_BITFIELD_CLASS_BIT(NullString); + STRINGISE_BITFIELD_CLASS_BIT(FixedArray); + STRINGISE_BITFIELD_CLASS_BIT(Union); } END_BITFIELD_STRINGISE(); } @@ -574,6 +667,7 @@ rdcstr DoStringise(const SDChunkFlags &el) STRINGISE_BITFIELD_CLASS_VALUE(NoFlags); STRINGISE_BITFIELD_CLASS_BIT(OpaqueChunk); + STRINGISE_BITFIELD_CLASS_BIT(HasCallstack); } END_BITFIELD_STRINGISE(); } diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index 15edfc4cb..4fefe5d82 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -90,7 +90,13 @@ public: static constexpr bool IsWriting() { return sertype == SerialiserMode::Writing; } bool ExportStructure() const { - return sertype == SerialiserMode::Reading && m_ExportStructured && !m_InternalElement; + // in debug builds, allow structured export during write for debugging. In release, only allow + // it on read to compile out the extra code on the writing path + return +#if ENABLED(RDOC_RELEASE) + sertype == SerialiserMode::Reading && +#endif + m_ExportStructured && !m_InternalElement; } enum ChunkFlags @@ -116,6 +122,11 @@ public: uint32_t GetChunkMetadataRecording() { return m_ChunkFlags; } void SetChunkMetadataRecording(uint32_t flags); +// debug-only option to dump out (roughly) the data going through the serialiser as it happens +#if ENABLED(RDOC_DEVEL) + void EnableDumping(FileIO::LogFileHandle *debugLog) { m_DebugDumpLog = debugLog; } +#endif + SDChunkMetaData &ChunkMetadata() { return m_ChunkMetadata; } ////////////////////////////////////////// // Utility functions @@ -1573,6 +1584,9 @@ private: } ChunkLookup m_ChunkLookup = NULL; +#if ENABLED(RDOC_DEVEL) + FileIO::LogFileHandle *m_DebugDumpLog = NULL; +#endif }; #ifndef SERIALISER_IMPL @@ -1695,7 +1709,7 @@ public: { FreeAlignedBuffer(m_Data); -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) Atomic::Dec64(&m_LiveChunks); Atomic::ExchAdd64(&m_TotalMem, -int64_t(m_Length)); #endif @@ -1706,7 +1720,7 @@ public: { return (ChunkType)m_ChunkType; } -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) static uint64_t NumLiveChunks() { return m_LiveChunks; } static uint64_t TotalMem() { return m_TotalMem; } #else @@ -1729,7 +1743,7 @@ public: ser.GetWriter()->Rewind(); -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) Atomic::Inc64(&m_LiveChunks); Atomic::ExchAdd64(&m_TotalMem, int64_t(m_Length)); #endif @@ -1746,7 +1760,7 @@ public: memcpy(ret->m_Data, m_Data, (size_t)m_Length); -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) Atomic::Inc64(&m_LiveChunks); Atomic::ExchAdd64(&m_TotalMem, int64_t(m_Length)); #endif @@ -1771,7 +1785,7 @@ private: uint32_t m_Length; byte *m_Data; -#if !defined(RELEASE) +#if ENABLED(RDOC_DEVEL) static int64_t m_LiveChunks, m_TotalMem; #endif };