From d1f25eea0f1a430cbdcbb79c94e683e8f4a84ebd Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 17 Dec 2018 17:07:25 +0000 Subject: [PATCH] Add extended thumbnail handling into XML codec --- renderdoc/core/core.cpp | 5 +- renderdoc/serialise/codecs/xml_codec.cpp | 153 ++++++++++++++++++----- renderdoc/serialise/rdcfile.cpp | 4 +- renderdoc/serialise/rdcfile.h | 2 +- 4 files changed, 130 insertions(+), 34 deletions(-) diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 27737a222..7cb432e72 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -1296,11 +1296,14 @@ void RenderDoc::FinishCaptureWriting(RDCFile *rdc, uint32_t frameNumber) props.version = 1; StreamWriter *w = rdc->WriteSection(props); + // if this file format ever changes, be sure to update the XML export which has a special + // handling for this case. + ExtThumbnailHeader header; header.width = thumb.width; header.height = thumb.height; header.len = thumb.len; - header.format = (uint32_t)thumb.format; + header.format = thumb.format; w->Write(header); w->Write(thumb.pixels, thumb.len); diff --git a/renderdoc/serialise/codecs/xml_codec.cpp b/renderdoc/serialise/codecs/xml_codec.cpp index e59d33f74..3170f04d1 100644 --- a/renderdoc/serialise/codecs/xml_codec.cpp +++ b/renderdoc/serialise/codecs/xml_codec.cpp @@ -29,6 +29,12 @@ #include "3rdparty/miniz/miniz.h" #include "3rdparty/pugixml/pugixml.hpp" +struct ThumbTypeAndData +{ + FileType format; + bytebuf data; +}; + static const char *typeNames[] = { "chunk", "struct", "array", "null", "buffer", "string", "enum", "uint", "int", "float", "bool", "char", "ResourceId", @@ -316,6 +322,36 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui StreamReader *reader = file.ReadSection(i); + if(props.type == SectionType::ExtendedThumbnail) + { + ExtThumbnailHeader thumbHeader = {}; + if(reader->Read(thumbHeader)) + { + // don't need to read the data, that's handled in Buffers2ZIP + bool succeeded = reader->SkipBytes(thumbHeader.len) && !reader->IsErrored(); + if(succeeded && (uint32_t)thumbHeader.format < (uint32_t)FileType::Count) + { + pugi::xml_node xExtThumbnail = xRoot.append_child("extended_thumbnail"); + + xExtThumbnail.append_attribute("width") = thumbHeader.width; + xExtThumbnail.append_attribute("height") = thumbHeader.height; + xExtThumbnail.append_attribute("length") = thumbHeader.len; + + if(thumbHeader.format == FileType::JPG) + xExtThumbnail.text() = "ext_thumb.jpg"; + else if(thumbHeader.format == FileType::PNG) + xExtThumbnail.text() = "ext_thumb.png"; + else if(thumbHeader.format == FileType::Raw) + xExtThumbnail.text() = "ext_thumb.raw"; + else + RDCERR("Unexpected extended thumbnail format %s", ToStr(thumbHeader.format).c_str()); + } + } + + delete reader; + continue; + } + pugi::xml_node xSection = xRoot.append_child("section"); if(props.flags & SectionFlags::ASCIIStored) @@ -506,7 +542,8 @@ static SDObject *XML2Obj(pugi::xml_node &obj) return ret; } -static ReplayStatus XML2Structured(const char *xml, FileType thumbFormat, const bytebuf &thumbBytes, +static ReplayStatus XML2Structured(const char *xml, const ThumbTypeAndData &thumb, + const ThumbTypeAndData &extThumb, const StructuredBufferList &buffers, RDCFile *rdc, uint64_t &version, StructuredChunkList &chunks, RENDERDOC_ProgressCallback progress) @@ -556,25 +593,47 @@ static ReplayStatus XML2Structured(const char *xml, FileType thumbFormat, const } RDCThumb th; - th.format = thumbFormat; + th.format = thumb.format; th.width = (uint16_t)xThumbnail.attribute("width").as_uint(); th.height = (uint16_t)xThumbnail.attribute("height").as_uint(); - RDCThumb *thumb = NULL; + RDCThumb *rdcthumb = NULL; - if(th.width > 0 && th.height > 0 && !thumbBytes.empty()) + if(th.width > 0 && th.height > 0 && !thumb.data.empty()) { - th.pixels = thumbBytes.data(); - th.len = (uint32_t)thumbBytes.size(); - thumb = &th; + th.pixels = thumb.data.data(); + th.len = (uint32_t)thumb.data.size(); + rdcthumb = &th; } - rdc->SetData(driver, driverName.c_str(), machineIdent, thumb); + rdc->SetData(driver, driverName.c_str(), machineIdent, rdcthumb); } // push in other sections pugi::xml_node xSection = xHeader.next_sibling(); + if(!strcmp(xSection.name(), "extended_thumbnail")) + { + SectionProperties props = {}; + props.type = SectionType::ExtendedThumbnail; + props.version = 1; + StreamWriter *w = rdc->WriteSection(props); + + ExtThumbnailHeader header; + header.width = (uint16_t)xSection.attribute("width").as_uint(); + header.height = (uint16_t)xSection.attribute("height").as_uint(); + header.len = (uint32_t)extThumb.data.size(); + header.format = extThumb.format; + w->Write(header); + w->Write(extThumb.data.data(), extThumb.data.size()); + + w->Finish(); + + delete w; + + xSection = xSection.next_sibling(); + } + if(progress) progress(StructuredProgress(0.1f)); @@ -762,14 +821,52 @@ static ReplayStatus Buffers2ZIP(const std::string &filename, const RDCFile &file RDCERR("Unexpected thumbnail format %s", ToStr(th.format).c_str()); } + for(int i = 0; i < file.NumSections(); i++) + { + const SectionProperties &props = file.GetSectionProperties(i); + + if(props.type == SectionType::ExtendedThumbnail) + { + StreamReader *reader = file.ReadSection(i); + + ExtThumbnailHeader thumbHeader = {}; + if(reader->Read(thumbHeader)) + { + byte *thumb_bytes = new byte[thumbHeader.len]; + + bool succeeded = reader->Read(thumb_bytes, thumbHeader.len) && !reader->IsErrored(); + if(succeeded && (uint32_t)thumbHeader.format < (uint32_t)FileType::Count) + { + if(thumbHeader.format == FileType::JPG) + mz_zip_writer_add_mem(&zip, "ext_thumb.jpg", thumb_bytes, thumbHeader.len, + MZ_BEST_COMPRESSION); + else if(thumbHeader.format == FileType::PNG) + mz_zip_writer_add_mem(&zip, "ext_thumb.png", thumb_bytes, thumbHeader.len, + MZ_BEST_COMPRESSION); + else if(thumbHeader.format == FileType::Raw) + mz_zip_writer_add_mem(&zip, "ext_thumb.raw", thumb_bytes, thumbHeader.len, + MZ_BEST_COMPRESSION); + else + RDCERR("Unexpected extended thumbnail format %s", ToStr(thumbHeader.format).c_str()); + } + + delete[] thumb_bytes; + } + + delete reader; + break; + } + } + mz_zip_writer_finalize_archive(&zip); mz_zip_writer_end(&zip); return ReplayStatus::Succeeded; } -static bool ZIP2Buffers(const std::string &filename, FileType &thumbFormat, bytebuf &thumbBytes, - StructuredBufferList &buffers, RENDERDOC_ProgressCallback progress) +static bool ZIP2Buffers(const std::string &filename, ThumbTypeAndData &thumb, + ThumbTypeAndData &extThumb, StructuredBufferList &buffers, + RENDERDOC_ProgressCallback progress) { std::string zipFile = filename; zipFile.erase(zipFile.size() - 4); // remove the .xml, leave only the .zip @@ -800,23 +897,20 @@ static bool ZIP2Buffers(const std::string &filename, FileType &thumbFormat, byte byte *buf = (byte *)mz_zip_reader_extract_to_heap(&zip, i, &sz, 0); - if(!strcmp(zstat.m_filename, "thumb.jpg")) + // thumbnails are stored separately + if(strstr(zstat.m_filename, "thumb")) { - // we store the thumbnail separately - thumbFormat = FileType::JPG; - thumbBytes.assign(buf, sz); - } - else if(!strcmp(zstat.m_filename, "thumb.png")) - { - // we store the thumbnail separately - thumbFormat = FileType::PNG; - thumbBytes.assign(buf, sz); - } - else if(!strcmp(zstat.m_filename, "thumb.raw")) - { - // we store the thumbnail separately - thumbFormat = FileType::Raw; - thumbBytes.assign(buf, sz); + FileType type = FileType::JPG; + if(strstr(zstat.m_filename, ".png")) + type = FileType::PNG; + else if(strstr(zstat.m_filename, ".raw")) + type = FileType::Raw; + + if(strstr(zstat.m_filename, "ext_thumb")) + { + extThumb.format = type; + extThumb.data.assign(buf, sz); + } } else { @@ -842,11 +936,10 @@ static bool ZIP2Buffers(const std::string &filename, FileType &thumbFormat, byte ReplayStatus importXMLZ(const char *filename, StreamReader &reader, RDCFile *rdc, SDFile &structData, RENDERDOC_ProgressCallback progress) { - FileType thumbFormat = FileType::JPG; - bytebuf thumbBytes; + ThumbTypeAndData thumb, extThumb; if(filename) { - bool success = ZIP2Buffers(filename, thumbFormat, thumbBytes, structData.buffers, progress); + bool success = ZIP2Buffers(filename, thumb, extThumb, structData.buffers, progress); if(!success) { RDCERR("Couldn't load zip to go with %s", filename); @@ -859,7 +952,7 @@ ReplayStatus importXMLZ(const char *filename, StreamReader &reader, RDCFile *rdc reader.Read(buf, (size_t)len); buf[len] = 0; - return XML2Structured(buf, thumbFormat, thumbBytes, structData.buffers, rdc, structData.version, + return XML2Structured(buf, thumb, extThumb, structData.buffers, rdc, structData.version, structData.chunks, progress); } diff --git a/renderdoc/serialise/rdcfile.cpp b/renderdoc/serialise/rdcfile.cpp index 0c2558ae3..428e50b77 100644 --- a/renderdoc/serialise/rdcfile.cpp +++ b/renderdoc/serialise/rdcfile.cpp @@ -592,12 +592,12 @@ void RDCFile::Init(StreamReader &reader) { thumbData = new byte[thumbHeader.len]; bool succeeded = thumbReader->Read(thumbData, thumbHeader.len) && !thumbReader->IsErrored(); - if(succeeded && thumbHeader.format < (uint32_t)FileType::Count) + if(succeeded && (uint32_t)thumbHeader.format < (uint32_t)FileType::Count) { m_Thumb.width = thumbHeader.width; m_Thumb.height = thumbHeader.height; m_Thumb.len = thumbHeader.len; - m_Thumb.format = (FileType)thumbHeader.format; + m_Thumb.format = thumbHeader.format; delete[] m_Thumb.pixels; m_Thumb.pixels = thumbData; } diff --git a/renderdoc/serialise/rdcfile.h b/renderdoc/serialise/rdcfile.h index b14aabe2e..46ad183b2 100644 --- a/renderdoc/serialise/rdcfile.h +++ b/renderdoc/serialise/rdcfile.h @@ -52,7 +52,7 @@ struct ExtThumbnailHeader uint16_t width; uint16_t height; uint32_t len; - uint32_t format; + FileType format; }; class RDCFile