From 680857cb0f87d61c98d883fb7e9c3063f7b27130 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 27 Aug 2020 15:54:01 +0100 Subject: [PATCH] Fix structured data conversion to preserve timestamp base * The timestamp base is queryable from the capture file and settable too, and conversions preserve un-rebased timestamps. Only rebasing when loading a capture for replay. --- renderdoc/api/replay/renderdoc_replay.h | 24 ++++++++++++++++++- renderdoc/core/core.cpp | 3 ++- renderdoc/core/core.h | 19 --------------- renderdoc/core/remote_server.cpp | 8 +++---- renderdoc/driver/d3d11/d3d11_context.cpp | 3 ++- renderdoc/driver/d3d11/d3d11_context.h | 2 ++ renderdoc/driver/d3d11/d3d11_device.cpp | 14 ++++++++++- renderdoc/driver/d3d11/d3d11_device.h | 4 ++++ renderdoc/driver/d3d12/d3d12_command_queue.h | 2 ++ renderdoc/driver/d3d12/d3d12_commands.cpp | 3 ++- renderdoc/driver/d3d12/d3d12_commands.h | 2 ++ renderdoc/driver/d3d12/d3d12_device.cpp | 14 ++++++++++- renderdoc/driver/d3d12/d3d12_device.h | 4 ++++ renderdoc/driver/gl/gl_driver.cpp | 17 +++++++++++-- renderdoc/driver/gl/gl_driver.h | 2 ++ renderdoc/driver/vulkan/vk_core.cpp | 17 +++++++++++-- renderdoc/driver/vulkan/vk_core.h | 2 ++ renderdoc/replay/capture_file.cpp | 12 ++++++---- renderdoc/serialise/codecs/xml_codec.cpp | 25 +++++++++++++++++++- renderdoc/serialise/rdcfile.cpp | 14 +++++++---- renderdoc/serialise/rdcfile.h | 6 ++++- renderdoc/serialise/serialiser.cpp | 2 -- renderdoc/serialise/serialiser.h | 7 ++++-- renderdoc/serialise/serialiser_tests.cpp | 8 +++---- 24 files changed, 162 insertions(+), 52 deletions(-) diff --git a/renderdoc/api/replay/renderdoc_replay.h b/renderdoc/api/replay/renderdoc_replay.h index 7f0a59ada..f4fbeca16 100644 --- a/renderdoc/api/replay/renderdoc_replay.h +++ b/renderdoc/api/replay/renderdoc_replay.h @@ -1455,6 +1455,22 @@ replay support. )"); virtual const char *RecordedMachineIdent() = 0; + DOCUMENT(R"(Retrieves the timestamp basis that all timestamps in the capture are relative to. May +be 0 if all timestamps are already absolute. + +:return: The timestamp base value +:rtype: ``int`` +)"); + virtual uint64_t TimestampBase() = 0; + + DOCUMENT(R"(Retrieves frequency for timestamps and durations to be divided by to convert to +microseconds. May be 1.0 if all timestamps and durations are already in microseconds. + +:return: The timestamp frequency +:rtype: ``float`` +)"); + virtual double TimestampFrequency() = 0; + DOCUMENT(R"(Sets the matadata for this capture handle. This function may only be called if the handle is 'empty' - i.e. no file has been opened with @@ -1475,9 +1491,15 @@ This function may only be called if the handle is 'empty' - i.e. no file has bee :param int thumbHeight: The height of the thumbnail. Ignored if :paramref:`SetMetadata.thumbData` is empty. :param bytes thumbData: The raw data of the thumbnail. If empty, no thumbnail is set. +:param int timeBase: The base value for timestamps in the capture. Can be set to 0 to indicate that + timestamps are already capture relative. +:param float timeFreq: The frequency for timestamps and durations to be divided by to convert to + microseconds. Can be set to 1.0 to indicate that timestamps and durations are already in + microseconds. )"); virtual void SetMetadata(const char *driverName, uint64_t machineIdent, FileType thumbType, - uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData) = 0; + uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData, + uint64_t timeBase, double timeFreq) = 0; DOCUMENT(R"(Opens a capture for replay locally and returns a handle to the capture. Only supported for handles opened with a native ``rdc`` capture, otherwise this will fail. diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 343ccf78d..228b0b161 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -1197,7 +1197,8 @@ RDCFile *RenderDoc::CreateRDC(RDCDriver driver, uint32_t frameNum, const FramePi EncodePixelsPNG(outRaw, outPng); } - ret->SetData(driver, ToStr(driver).c_str(), OSUtility::GetMachineIdent(), &outPng); + ret->SetData(driver, ToStr(driver).c_str(), OSUtility::GetMachineIdent(), &outPng, m_TimeBase, + m_TimeFrequency); FileIO::CreateParentDirectory(m_CurrentLogFile); diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index 51e94d96a..310bbc0fd 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -410,25 +410,6 @@ public: void Initialise(); void RemoveHooks(); - // these timestamp parameters are set while capturing to the base tick-count and tick frequency of - // the global timer, which will be saved with any new capture to convert timestamps and durations - // in ticks into microseconds. Older captures serialised timestamps and durations as microseconds - // directly. On replay these are set when the capture is first loaded and used to convert any - // serialised timestamps and durations. If an old capture is serialised, they will be set to base - // = 0 and frequency = 1.0 to ensure no conversion happens. - void SetGlobalTimestampParameters(uint64_t base, double frequency) - { - if(IsReplayApp()) - { - m_TimeBase = base; - m_TimeFrequency = frequency; - } - } - void GetGlobalTimestampParameters(uint64_t &base, double &frequency) - { - base = m_TimeBase; - frequency = m_TimeFrequency; - } const GlobalEnvironment &GetGlobalEnvironment() { return m_GlobalEnv; } void InitialiseReplay(GlobalEnvironment env, const rdcarray &args); void ShutdownReplay(); diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index bcd81f641..96b6f026c 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -270,8 +270,8 @@ static void ActiveRemoteClientThread(ClientThread *threadData, if(RemoteServer_DebugLogging()) { - reader.ConfigureStructuredExport(&GetRemoteServerChunkName, false); - writer.ConfigureStructuredExport(&GetRemoteServerChunkName, false); + reader.ConfigureStructuredExport(&GetRemoteServerChunkName, false, 0, 1.0); + writer.ConfigureStructuredExport(&GetRemoteServerChunkName, false, 0, 1.0); rdcstr filename = FileIO::GetTempFolderFilename() + "/RenderDoc/RemoteServer_Server.log"; @@ -1228,8 +1228,8 @@ RemoteServer::RemoteServer(Network::Socket *sock, const rdcstr &deviceID) if(RemoteServer_DebugLogging()) { - reader->ConfigureStructuredExport(&GetRemoteServerChunkName, false); - writer->ConfigureStructuredExport(&GetRemoteServerChunkName, false); + reader->ConfigureStructuredExport(&GetRemoteServerChunkName, false, 0, 1.0); + writer->ConfigureStructuredExport(&GetRemoteServerChunkName, false, 0, 1.0); rdcstr filename = FileIO::GetTempFolderFilename() + "/RenderDoc/RemoteServer_Client.log"; diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 05fd0d74f..54bb55632 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -1209,7 +1209,8 @@ ReplayStatus WrappedID3D11DeviceContext::ReplayLog(CaptureState readType, uint32 if(IsLoading(m_State) || IsStructuredExporting(m_State)) { - ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State)); + ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State), + m_pDevice->GetTimeBase(), m_pDevice->GetTimeFrequency()); ser.GetStructuredFile().Swap(m_pDevice->GetStructuredFile()); diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index f97ec46ce..8f00ed2ca 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -204,6 +204,8 @@ private: rdcarray m_AnnotationQueue; Threading::CriticalSection m_AnnotLock; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile = NULL; uint64_t m_CurChunkOffset; diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index 897298d7e..d80fa7342 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -1222,6 +1222,18 @@ ReplayStatus WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool store StreamReader *reader = rdc->ReadSection(sectionIdx); + if(IsStructuredExporting(m_State)) + { + // when structured exporting don't do any timebase conversion + m_TimeBase = 0; + m_TimeFrequency = 1.0; + } + else + { + m_TimeBase = rdc->GetTimestampBase(); + m_TimeFrequency = rdc->GetTimestampFrequency(); + } + if(reader->IsErrored()) { delete reader; @@ -1233,7 +1245,7 @@ ReplayStatus WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool store ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers, m_TimeBase, m_TimeFrequency); m_StructuredFile = &ser.GetStructuredFile(); diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index ced44b7d8..2b51694d6 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -381,6 +381,8 @@ private: CaptureFailReason m_FailedReason; uint32_t m_Failures = 0; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile = NULL; SDFile m_StoredStructuredData; @@ -444,6 +446,8 @@ public: void UnlockForChunkRemoval(); SDFile &GetStructuredFile() { return *m_StructuredFile; } + uint64_t GetTimeBase() { return m_TimeBase; } + double GetTimeFrequency() { return m_TimeFrequency; } void FirstFrame(IDXGISwapper *swapper); rdcarray GetDebugMessages(); diff --git a/renderdoc/driver/d3d12/d3d12_command_queue.h b/renderdoc/driver/d3d12/d3d12_command_queue.h index b9f22af46..e0bbb6156 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue.h +++ b/renderdoc/driver/d3d12/d3d12_command_queue.h @@ -126,6 +126,8 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue, StreamReader *m_FrameReader = NULL; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile = NULL; // command recording/replay data shared between queues and lists diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index f7cc44b5d..23622d47f 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -841,7 +841,8 @@ ReplayStatus WrappedID3D12CommandQueue::ReplayLog(CaptureState readType, uint32_ if(IsLoading(m_State) || IsStructuredExporting(m_State)) { - ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State)); + ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State), + m_pDevice->GetTimeBase(), m_pDevice->GetTimeFrequency()); ser.GetStructuredFile().Swap(m_pDevice->GetStructuredFile()); diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h index 2c7f6094b..f739dcbeb 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.h +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -346,6 +346,8 @@ struct D3D12CommandData ResourceId m_LastPresentedImage; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile; std::map > m_ResourceUses; diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index e9a7ccb3e..cb27149b0 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -3193,6 +3193,18 @@ ReplayStatus WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool store StreamReader *reader = rdc->ReadSection(sectionIdx); + if(IsStructuredExporting(m_State)) + { + // when structured exporting don't do any timebase conversion + m_TimeBase = 0; + m_TimeFrequency = 1.0; + } + else + { + m_TimeBase = rdc->GetTimestampBase(); + m_TimeFrequency = rdc->GetTimestampFrequency(); + } + if(reader->IsErrored()) { delete reader; @@ -3206,7 +3218,7 @@ ReplayStatus WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool store ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers, m_TimeBase, m_TimeFrequency); m_StructuredFile = &ser.GetStructuredFile(); diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index b859c6c35..1cd78ba8c 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -438,6 +438,8 @@ private: rdcarray m_DebugMessages; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile = NULL; SDFile m_StoredStructuredData; @@ -684,6 +686,8 @@ public: m_State = CaptureState::StructuredExport; } SDFile &GetStructuredFile() { return *m_StructuredFile; } + uint64_t GetTimeBase() { return m_TimeBase; } + double GetTimeFrequency() { return m_TimeFrequency; } // interface for DXGI virtual IUnknown *GetRealIUnknown() { return GetReal(); } void *GetFrameCapturerDevice() { return (ID3D12Device *)this; } diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 89d29ad12..d78bdd5a8 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -3243,6 +3243,18 @@ ReplayStatus WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStruct StreamReader *reader = rdc->ReadSection(sectionIdx); + if(IsStructuredExporting(m_State)) + { + // when structured exporting don't do any timebase conversion + m_TimeBase = 0; + m_TimeFrequency = 1.0; + } + else + { + m_TimeBase = rdc->GetTimestampBase(); + m_TimeFrequency = rdc->GetTimestampFrequency(); + } + if(reader->IsErrored()) { delete reader; @@ -3254,7 +3266,7 @@ ReplayStatus WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStruct ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers, m_TimeBase, m_TimeFrequency); m_StructuredFile = &ser.GetStructuredFile(); @@ -5014,7 +5026,8 @@ ReplayStatus WrappedOpenGL::ContextReplayLog(CaptureState readType, uint32_t sta if(IsLoading(m_State) || IsStructuredExporting(m_State)) { - ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State)); + ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State), m_TimeBase, + m_TimeFrequency); ser.GetStructuredFile().Swap(*m_StructuredFile); diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 426213542..391f22848 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -209,6 +209,8 @@ private: GLResourceManager *m_ResourceManager; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile; SDFile m_StoredStructuredData; diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 035eef2b1..07c12447f 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -2211,6 +2211,18 @@ ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStruct StreamReader *reader = rdc->ReadSection(sectionIdx); + if(IsStructuredExporting(m_State)) + { + // when structured exporting don't do any timebase conversion + m_TimeBase = 0; + m_TimeFrequency = 1.0; + } + else + { + m_TimeBase = rdc->GetTimestampBase(); + m_TimeFrequency = rdc->GetTimestampFrequency(); + } + if(reader->IsErrored()) { delete reader; @@ -2222,7 +2234,7 @@ ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStruct ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers, m_TimeBase, m_TimeFrequency); m_StructuredFile = &ser.GetStructuredFile(); @@ -2411,7 +2423,8 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta if(IsLoading(m_State) || IsStructuredExporting(m_State)) { - ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State)); + ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State), m_TimeBase, + m_TimeFrequency); ser.GetStructuredFile().Swap(*m_StructuredFile); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index cb8f9a0f1..92842a4bb 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -348,6 +348,8 @@ private: VulkanDrawcallCallback *m_DrawcallCallback; void *m_SubmitChain; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0f; SDFile *m_StructuredFile; SDFile m_StoredStructuredData; diff --git a/renderdoc/replay/capture_file.cpp b/renderdoc/replay/capture_file.cpp index dd4d7159b..22092dfc1 100644 --- a/renderdoc/replay/capture_file.cpp +++ b/renderdoc/replay/capture_file.cpp @@ -113,11 +113,14 @@ public: ReplaySupport LocalReplaySupport() { return m_Support; } rdcstr DriverName() { return m_DriverName; } const char *RecordedMachineIdent() { return m_Ident.c_str(); } + uint64_t TimestampBase() { return m_RDC ? m_RDC->GetTimestampBase() : 0; } + double TimestampFrequency() { return m_RDC ? m_RDC->GetTimestampFrequency() : 1.0; } rdcpair OpenCapture(const ReplayOptions &opts, RENDERDOC_ProgressCallback progress); void SetMetadata(const char *driverName, uint64_t machineIdent, FileType thumbType, - uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData); + uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData, + uint64_t timeBase, double timeFreq); ReplayStatus Convert(const char *filename, const char *filetype, const SDFile *file, RENDERDOC_ProgressCallback progress); @@ -369,7 +372,8 @@ rdcpair CaptureFile::OpenCapture(const Replay } void CaptureFile::SetMetadata(const char *driverName, uint64_t machineIdent, FileType thumbType, - uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData) + uint32_t thumbWidth, uint32_t thumbHeight, const bytebuf &thumbData, + uint64_t timeBase, double timeFreq) { if(m_RDC) { @@ -395,7 +399,7 @@ void CaptureFile::SetMetadata(const char *driverName, uint64_t machineIdent, Fil } m_RDC = new RDCFile; - m_RDC->SetData(driver, driverName, machineIdent, thumb); + m_RDC->SetData(driver, driverName, machineIdent, thumb, timeBase, timeFreq); } ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype, const SDFile *file, @@ -438,7 +442,7 @@ ReplayStatus CaptureFile::Convert(const char *filename, const char *filetype, co RDCFile output; output.SetData(m_RDC->GetDriver(), m_RDC->GetDriverName().c_str(), m_RDC->GetMachineIdent(), - &m_RDC->GetThumbnail()); + &m_RDC->GetThumbnail(), m_RDC->GetTimestampBase(), m_RDC->GetTimestampFrequency()); output.Create(filename); diff --git a/renderdoc/serialise/codecs/xml_codec.cpp b/renderdoc/serialise/codecs/xml_codec.cpp index 3df12dbb6..8887423d0 100644 --- a/renderdoc/serialise/codecs/xml_codec.cpp +++ b/renderdoc/serialise/codecs/xml_codec.cpp @@ -310,6 +310,11 @@ static ReplayStatus Structured2XML(const char *filename, const RDCFile &file, ui else RDCERR("Unexpected thumbnail format %s", ToStr(th.format).c_str()); } + + pugi::xml_node xTimebase = xHeader.append_child("timebase"); + + xTimebase.append_attribute("base") = file.GetTimestampBase(); + xTimebase.append_attribute("frequency") = file.GetTimestampFrequency(); } if(progress) @@ -595,6 +600,24 @@ static ReplayStatus XML2Structured(const char *xml, const ThumbTypeAndData &thum return ReplayStatus::FileCorrupted; } + pugi::xml_node xTimebase = xThumbnail.next_sibling(); + + uint64_t timeBase = 0; + double timeFreq = 1.0; + + // newer XML documents have the timebase here, allow conversion without it + if(xTimebase) + { + if(strcmp(xTimebase.name(), "timebase") != 0) + { + RDCERR("Malformed document, expected driver node"); + return ReplayStatus::FileCorrupted; + } + + timeBase = xTimebase.attribute("base").as_ullong(); + timeFreq = xTimebase.attribute("frequency").as_double(); + } + RDCThumb th; th.format = thumb.format; th.width = (uint16_t)xThumbnail.attribute("width").as_uint(); @@ -608,7 +631,7 @@ static ReplayStatus XML2Structured(const char *xml, const ThumbTypeAndData &thum rdcthumb = &th; } - rdc->SetData(driver, driverName.c_str(), machineIdent, rdcthumb); + rdc->SetData(driver, driverName.c_str(), machineIdent, rdcthumb, timeBase, timeFreq); } if(progress) diff --git a/renderdoc/serialise/rdcfile.cpp b/renderdoc/serialise/rdcfile.cpp index 2e206ad17..29a665d95 100644 --- a/renderdoc/serialise/rdcfile.cpp +++ b/renderdoc/serialise/rdcfile.cpp @@ -297,6 +297,8 @@ void RDCFile::Open(const char *path) m_Driver = RDCDriver::Image; m_DriverName = "Image"; m_MachineIdent = 0; + m_TimeBase = 0; + m_TimeFrequency = 1.0; return; } } @@ -419,9 +421,8 @@ void RDCFile::Init(StreamReader &reader) } } - // explicitly set this, so if we load an old capture with no timebase it gets reset back to a good - // default state even if we previously opened a capture with a timebase - RenderDoc::Inst().SetGlobalTimestampParameters(timeBase.timeBase, timeBase.timeFreq); + m_TimeBase = timeBase.timeBase; + m_TimeFrequency = timeBase.timeFreq; m_Driver = meta.driverID; m_DriverName = driverName; @@ -664,7 +665,7 @@ bool RDCFile::CopyFileTo(const char *filename) } void RDCFile::SetData(RDCDriver driver, const char *driverName, uint64_t machineIdent, - const RDCThumb *thumb) + const RDCThumb *thumb, uint64_t timeBase, double timeFreq) { m_Driver = driver; m_DriverName = driverName; @@ -673,6 +674,8 @@ void RDCFile::SetData(RDCDriver driver, const char *driverName, uint64_t machine { m_Thumb = *thumb; } + m_TimeBase = timeBase; + m_TimeFrequency = timeFreq; } void RDCFile::Create(const char *filename) @@ -751,7 +754,8 @@ void RDCFile::Create(const char *filename) sizeof(CaptureTimeBase); CaptureTimeBase timeBase; - RenderDoc::Inst().GetGlobalTimestampParameters(timeBase.timeBase, timeBase.timeFreq); + timeBase.timeBase = m_TimeBase; + timeBase.timeFreq = m_TimeFrequency; { StreamWriter writer(m_File, Ownership::Nothing); diff --git a/renderdoc/serialise/rdcfile.h b/renderdoc/serialise/rdcfile.h index 42ae24b69..c4ea3d086 100644 --- a/renderdoc/serialise/rdcfile.h +++ b/renderdoc/serialise/rdcfile.h @@ -78,7 +78,7 @@ public: // Sets the parameters of an RDCFile in memory. void SetData(RDCDriver driver, const char *driverName, uint64_t machineIdent, - const RDCThumb *thumb); + const RDCThumb *thumb, uint64_t timeBase, double timeFreq); // creates a new file with current properties, file will be overwritten if it already exists void Create(const char *filename); @@ -88,6 +88,8 @@ public: RDCDriver GetDriver() const { return m_Driver; } const rdcstr &GetDriverName() const { return m_DriverName; } uint64_t GetMachineIdent() const { return m_MachineIdent; } + uint64_t GetTimestampBase() const { return m_TimeBase; } + double GetTimestampFrequency() const { return m_TimeFrequency; } const RDCThumb &GetThumbnail() const { return m_Thumb; } int SectionIndex(SectionType type) const; int SectionIndex(const char *name) const; @@ -114,6 +116,8 @@ private: RDCDriver m_Driver = RDCDriver::Unknown; rdcstr m_DriverName; uint64_t m_MachineIdent = 0; + uint64_t m_TimeBase = 0; + double m_TimeFrequency = 1.0; RDCThumb m_Thumb; ContainerError m_Error = ContainerError::NoError; diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index 2bedcd956..b607243e4 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -97,8 +97,6 @@ Serialiser::Serialiser(StreamReader *reader, Ownership if(rootStructuredObj) m_StructureStack.push_back(rootStructuredObj); - - RenderDoc::Inst().GetGlobalTimestampParameters(m_TimerBase, m_TimerFrequency); } template <> diff --git a/renderdoc/serialise/serialiser.h b/renderdoc/serialise/serialiser.h index 7455602ea..6985cbc87 100644 --- a/renderdoc/serialise/serialiser.h +++ b/renderdoc/serialise/serialiser.h @@ -163,11 +163,14 @@ public: ////////////////////////////////////////// // Public serialisation interface - void ConfigureStructuredExport(ChunkLookup lookup, bool includeBuffers) + void ConfigureStructuredExport(ChunkLookup lookup, bool includeBuffers, uint64_t timeBase, + double timeFreq) { m_ChunkLookup = lookup; m_ExportBuffers = includeBuffers; m_ExportStructured = (lookup != NULL); + m_TimerBase = timeBase; + m_TimerFrequency = timeFreq; } uint32_t BeginChunk(uint32_t chunkID, uint64_t byteLength); @@ -1377,7 +1380,7 @@ public: StructuredSerialiser(SDObject *obj, ChunkLookup lookup) : Serialiser(new StreamReader(StreamReader::DummyStream), Ownership::Stream, obj) { - ConfigureStructuredExport(lookup, false); + ConfigureStructuredExport(lookup, false, 0, 1.0); SetStreamingMode(true); SetDummy(true); } diff --git a/renderdoc/serialise/serialiser_tests.cpp b/renderdoc/serialise/serialiser_tests.cpp index 2e6d3ceb6..e23763478 100644 --- a/renderdoc/serialise/serialiser_tests.cpp +++ b/renderdoc/serialise/serialiser_tests.cpp @@ -189,7 +189,7 @@ TEST_CASE("Read/write via structured of basic types", "[serialiser]") ChunkLookup testChunkLoop = [](uint32_t) -> rdcstr { return "TestChunk"; }; - ser.ConfigureStructuredExport(testChunkLoop, true); + ser.ConfigureStructuredExport(testChunkLoop, true, 0, 1.0); int64_t a; uint64_t b; @@ -654,7 +654,7 @@ TEST_CASE("Read/write chunk metadata", "[serialiser]") ChunkLookup testChunkLoop = [](uint32_t) -> rdcstr { return "TestChunk"; }; - ser.ConfigureStructuredExport(testChunkLoop, true); + ser.ConfigureStructuredExport(testChunkLoop, true, 0, 1.0); ser.ReadChunk(); @@ -908,7 +908,7 @@ TEST_CASE("Read/write container types", "[serialiser][structured]") { ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream); - ser.ConfigureStructuredExport([](uint32_t) -> rdcstr { return "TestChunk"; }, true); + ser.ConfigureStructuredExport([](uint32_t) -> rdcstr { return "TestChunk"; }, true, 0, 1.0); ser.ReadChunk(); { @@ -1188,7 +1188,7 @@ TEST_CASE("Read/write complex types", "[serialiser][structured]") { ReadSerialiser ser(new StreamReader(buf->GetData(), buf->GetOffset()), Ownership::Stream); - ser.ConfigureStructuredExport([](uint32_t) -> rdcstr { return "TestChunk"; }, true); + ser.ConfigureStructuredExport([](uint32_t) -> rdcstr { return "TestChunk"; }, true, 0, 1.0); ser.ReadChunk(); {