diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index b962ff0c2..baaa159e2 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -784,6 +784,13 @@ void RenderDoc::RegisterRemoteProvider(RDCDriver driver, const char *name, m_RemoteDriverProviders[driver] = provider; } +void RenderDoc::RegisterStructuredProcessor(RDCDriver driver, StructuredProcessor provider) +{ + RDCASSERT(m_StructProcesssors.find(driver) == m_StructProcesssors.end()); + + m_StructProcesssors[driver] = provider; +} + void RenderDoc::RegisterCaptureExporter(const char *filetype, const char *description, CaptureExporter exporter) { @@ -805,6 +812,16 @@ void RenderDoc::RegisterCaptureImportExporter(const char *filetype, const char * m_Exporters[filetype] = exporter; } +StructuredProcessor RenderDoc::GetStructuredProcessor(RDCDriver driver) +{ + auto it = m_StructProcesssors.find(driver); + + if(it == m_StructProcesssors.end()) + return NULL; + + return it->second; +} + CaptureExporter RenderDoc::GetCaptureExporter(const char *filetype) { auto it = m_Exporters.find(filetype); diff --git a/renderdoc/core/core.h b/renderdoc/core/core.h index add74c67c..7254a00e7 100644 --- a/renderdoc/core/core.h +++ b/renderdoc/core/core.h @@ -142,6 +142,11 @@ constexpr inline bool IsActiveCapturing(CaptureState state) return state == CaptureState::ActiveCapturing; } +constexpr inline bool IsStructuredExporting(CaptureState state) +{ + return state == CaptureState::StructuredExport; +} + enum class SystemChunk : uint32_t { // 0 is reserved as a 'null' chunk that is only for debug @@ -232,6 +237,8 @@ class RDCFile; typedef ReplayStatus (*RemoteDriverProvider)(RDCFile *rdc, IRemoteDriver **driver); typedef ReplayStatus (*ReplayDriverProvider)(RDCFile *rdc, IReplayDriver **driver); +typedef void (*StructuredProcessor)(RDCFile *rdc, SDFile &structData); + typedef ReplayStatus (*CaptureImporter)(const char *filename, StreamReader &reader, RDCFile *rdc, SDFile &structData); typedef ReplayStatus (*CaptureExporter)(const char *filename, const RDCFile &rdc, @@ -311,11 +318,15 @@ public: void RegisterReplayProvider(RDCDriver driver, const char *name, ReplayDriverProvider provider); void RegisterRemoteProvider(RDCDriver driver, const char *name, RemoteDriverProvider provider); + void RegisterStructuredProcessor(RDCDriver driver, StructuredProcessor provider); + void RegisterCaptureExporter(const char *filetype, const char *description, CaptureExporter exporter); void RegisterCaptureImportExporter(const char *filetype, const char *description, CaptureImporter importer, CaptureExporter exporter); + StructuredProcessor GetStructuredProcessor(RDCDriver driver); + CaptureExporter GetCaptureExporter(const char *filetype); CaptureImporter GetCaptureImporter(const char *filetype); @@ -462,6 +473,8 @@ private: map m_ReplayDriverProviders; map m_RemoteDriverProviders; + std::map m_StructProcesssors; + std::map m_ImportExportFormats; std::map m_Importers; std::map m_Exporters; @@ -542,6 +555,14 @@ struct DriverRegistration } }; +struct StructuredProcessRegistration +{ + StructuredProcessRegistration(RDCDriver driver, StructuredProcessor provider) + { + RenderDoc::Inst().RegisterStructuredProcessor(driver, provider); + } +}; + struct ConversionRegistration { ConversionRegistration(const char *filetype, const char *description, CaptureImporter importer, diff --git a/renderdoc/core/image_viewer.cpp b/renderdoc/core/image_viewer.cpp index 98f7e0081..fa342080a 100644 --- a/renderdoc/core/image_viewer.cpp +++ b/renderdoc/core/image_viewer.cpp @@ -148,7 +148,7 @@ public: FrameRecord GetFrameRecord() { return m_FrameRecord; } const D3D11Pipe::State &GetD3D11PipelineState() { return m_PipelineState; } // other operations are dropped/ignored, to avoid confusion - void ReadLogInitialisation(RDCFile *rdc) {} + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) {} void RenderMesh(uint32_t eventID, const vector &secondaryDraws, const MeshDisplay &cfg) { } diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index cd69a9647..79e89cb9a 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -424,7 +424,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData) } else { - driver->ReadLogInitialisation(rdc); + driver->ReadLogInitialisation(rdc, false); RenderDoc::Inst().SetProgressPtr(NULL); diff --git a/renderdoc/core/replay_proxy.h b/renderdoc/core/replay_proxy.h index d29f5f701..a54bb66dc 100644 --- a/renderdoc/core/replay_proxy.h +++ b/renderdoc/core/replay_proxy.h @@ -115,7 +115,7 @@ public: bool IsRemoteProxy() { return !m_RemoteServer; } void Shutdown() { delete this; } - void ReadLogInitialisation(RDCFile *rdc) {} + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) {} vector GetSupportedWindowSystems() { if(m_Proxy) diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index fbf67ee10..e1735ac7f 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -97,23 +97,27 @@ WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device *real D3D11_FEATURE_DATA_D3D11_OPTIONS features; RDCEraseEl(features); - HRESULT hr = - m_pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)); + HRESULT hr = S_OK; + + if(m_pRealContext) + hr = m_pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features)); m_SetCBuffer1 = false; if(SUCCEEDED(hr)) m_SetCBuffer1 = features.ConstantBufferOffsetting == TRUE; m_pRealContext1 = NULL; - m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&m_pRealContext1); - m_pRealContext2 = NULL; - m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext2), (void **)&m_pRealContext2); - m_pRealContext3 = NULL; - m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext3), (void **)&m_pRealContext3); + if(m_pRealContext) + { + m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&m_pRealContext1); + m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext2), (void **)&m_pRealContext2); + m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext3), (void **)&m_pRealContext3); + } m_NeedUpdateSubWorkaround = false; + if(m_pRealContext) { D3D11_FEATURE_DATA_THREADING caps = {FALSE, FALSE}; @@ -167,7 +171,7 @@ WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device *real m_DeferredSavedState = NULL; m_DoStateVerify = IsCaptureMode(m_State); - if(context->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) + if(!context || context->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) { m_CurrentPipelineState->SetImmediatePipeline(m_pDevice); } @@ -188,7 +192,7 @@ WrappedID3D11DeviceContext::~WrappedID3D11DeviceContext() if(m_ContextRecord) m_ContextRecord->Delete(m_pDevice->GetResourceManager()); - if(m_pRealContext->GetType() != D3D11_DEVICE_CONTEXT_IMMEDIATE) + if(m_pRealContext && m_pRealContext->GetType() != D3D11_DEVICE_CONTEXT_IMMEDIATE) m_pDevice->RemoveDeferredContext(this); for(auto it = m_StreamOutCounters.begin(); it != m_StreamOutCounters.end(); ++it) @@ -1049,8 +1053,12 @@ void WrappedID3D11DeviceContext::ReplayLog(CaptureState readType, uint32_t start ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - if(IsLoading(m_State)) - ser.ConfigureStructuredExport(&GetChunkName, false); + if(IsLoading(m_State) || IsStructuredExporting(m_State)) + { + ser.ConfigureStructuredExport(&GetChunkName, IsStructuredExporting(m_State)); + + ser.GetStructuredFile().swap(m_pDevice->GetStructuredFile()); + } m_DoStateVerify = true; @@ -1196,6 +1204,10 @@ void WrappedID3D11DeviceContext::ReplayLog(CaptureState readType, uint32_t start // RDCDEBUG("Can skip %d initial states.", initialSkips); } + // swap the structure back now that we've accumulated the frame as well. + if(IsLoading(m_State) || IsStructuredExporting(m_State)) + ser.GetStructuredFile().swap(m_pDevice->GetStructuredFile()); + m_pDevice->GetResourceManager()->MarkInFrame(false); m_DoStateVerify = false; diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index 4083b4fb2..673f3c3b0 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -68,17 +68,19 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device *realDevice, D3D11InitPara m_ScratchSerialiser.SetChunkMetadataRecording(flags); + m_StructuredFile = &m_StoredStructuredData; + m_pDevice1 = NULL; - m_pDevice->QueryInterface(__uuidof(ID3D11Device1), (void **)&m_pDevice1); - m_pDevice2 = NULL; - m_pDevice->QueryInterface(__uuidof(ID3D11Device2), (void **)&m_pDevice2); - m_pDevice3 = NULL; - m_pDevice->QueryInterface(__uuidof(ID3D11Device3), (void **)&m_pDevice3); - m_pDevice4 = NULL; - m_pDevice->QueryInterface(__uuidof(ID3D11Device4), (void **)&m_pDevice4); + if(m_pDevice) + { + m_pDevice->QueryInterface(__uuidof(ID3D11Device1), (void **)&m_pDevice1); + m_pDevice->QueryInterface(__uuidof(ID3D11Device2), (void **)&m_pDevice2); + m_pDevice->QueryInterface(__uuidof(ID3D11Device3), (void **)&m_pDevice3); + m_pDevice->QueryInterface(__uuidof(ID3D11Device4), (void **)&m_pDevice4); + } m_Replay.SetDevice(this); @@ -104,12 +106,6 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device *realDevice, D3D11InitPara m_AppControlledCapture = false; -#if ENABLED(RDOC_RELEASE) - const bool debugSerialiser = false; -#else - const bool debugSerialiser = true; -#endif - if(RenderDoc::Inst().IsReplayApp()) { m_State = CaptureState::LoadingReplaying; @@ -148,17 +144,22 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device *realDevice, D3D11InitPara } ID3D11DeviceContext *context = NULL; - realDevice->GetImmediateContext(&context); + if(realDevice) + realDevice->GetImmediateContext(&context); m_pImmediateContext = new WrappedID3D11DeviceContext(this, context); - realDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&m_pInfoQueue); - realDevice->QueryInterface(__uuidof(ID3D11Debug), (void **)&m_WrappedDebug.m_pDebug); + m_pInfoQueue = NULL; + if(realDevice) + { + realDevice->QueryInterface(__uuidof(ID3D11InfoQueue), (void **)&m_pInfoQueue); + realDevice->QueryInterface(__uuidof(ID3D11Debug), (void **)&m_WrappedDebug.m_pDebug); + } // useful for marking regions during replay for self-captures m_RealAnnotations = NULL; - m_pImmediateContext->GetReal()->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), - (void **)&m_RealAnnotations); + if(context) + context->QueryInterface(__uuidof(ID3DUserDefinedAnnotation), (void **)&m_RealAnnotations); if(m_pInfoQueue) { @@ -186,12 +187,13 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device *realDevice, D3D11InitPara if(RenderDoc::Inst().IsReplayApp()) m_pInfoQueue->SetMuteDebugOutput(false); } - else + else if(m_pDevice) { RDCDEBUG("Couldn't get ID3D11InfoQueue."); } - m_InitParams = *params; + if(params) + m_InitParams = *params; // ATI workaround - these dlls can get unloaded and cause a crash. @@ -752,8 +754,11 @@ void WrappedID3D11Device::ProcessChunk(ReadSerialiser &ser, D3D11Chunk context) // add a reference for the resource manager - normally it takes ownership of the resource on // creation and releases it // to destruction, but we want to control our immediate context ourselves. - m_pImmediateContext->AddRef(); - m_ResourceManager->AddLiveResource(ImmediateContext, m_pImmediateContext); + if(IsReplayingAndReading()) + { + m_pImmediateContext->AddRef(); + m_ResourceManager->AddLiveResource(ImmediateContext, m_pImmediateContext); + } break; } case D3D11Chunk::SetResourceName: Serialise_SetResourceName(ser, 0x0, ""); break; @@ -901,7 +906,7 @@ void WrappedID3D11Device::Serialise_CaptureScope(SerialiserType &ser) } } -void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc) +void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) { int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture); @@ -918,8 +923,11 @@ void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc) ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - // TODO make this an option passed in - ser.ConfigureStructuredExport(&GetChunkName, false); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + + m_StructuredFile = &ser.GetStructuredFile(); + + m_StoredStructuredData.version = m_StructuredFile->version = m_SectionVersion; int chunkIdx = 0; @@ -964,7 +972,8 @@ void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc) m_pImmediateContext->SetFrameReader(new StreamReader(reader, frameDataSize)); - GetResourceManager()->ApplyInitialContents(); + if(!IsStructuredExporting(m_State)) + GetResourceManager()->ApplyInitialContents(); m_pImmediateContext->ReplayLog(m_State, 0, 0, false); } @@ -977,8 +986,17 @@ void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc) break; } - DrawcallDescription *previous = NULL; - SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous); + // steal the structured data for ourselves + m_StructuredFile->swap(m_StoredStructuredData); + + // and in future use this file. + m_StructuredFile = &m_StoredStructuredData; + + if(!IsStructuredExporting(m_State)) + { + DrawcallDescription *previous = NULL; + SetupDrawcallPointers(&m_Drawcalls, GetFrameRecord().drawcallList, NULL, previous); + } #if ENABLED(RDOC_DEVEL) for(auto it = chunkInfos.begin(); it != chunkInfos.end(); ++it) diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index 1a91b0ce4..85a611dbb 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -393,6 +393,9 @@ private: CaptureFailReason m_FailedReason; uint32_t m_Failures; + SDFile *m_StructuredFile = NULL; + SDFile m_StoredStructuredData; + vector m_DebugMessages; vector m_CapturedFrames; @@ -440,6 +443,7 @@ public: void LockForChunkRemoval(); void UnlockForChunkRemoval(); + SDFile &GetStructuredFile() { return *m_StructuredFile; } void FirstFrame(WrappedIDXGISwapChain4 *swapChain); std::vector GetDebugMessages(); @@ -500,7 +504,12 @@ public: void Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData); void Apply_InitialState(ID3D11DeviceChild *live, D3D11ResourceManager::InitialContentData initial); - void ReadLogInitialisation(RDCFile *rdc); + void SetStructuredExport(uint64_t sectionVersion) + { + m_SectionVersion = sectionVersion; + m_State = CaptureState::StructuredExport; + } + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers); void ProcessChunk(ReadSerialiser &ser, D3D11Chunk context); void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); diff --git a/renderdoc/driver/d3d11/d3d11_initstate.cpp b/renderdoc/driver/d3d11/d3d11_initstate.cpp index 20bb41807..fe82cb8e6 100644 --- a/renderdoc/driver/d3d11/d3d11_initstate.cpp +++ b/renderdoc/driver/d3d11/d3d11_initstate.cpp @@ -934,6 +934,9 @@ bool WrappedID3D11Device::Serialise_InitialState(SerialiserType &ser, ResourceId void WrappedID3D11Device::Create_InitialState(ResourceId id, ID3D11DeviceChild *live, bool hasData) { + if(IsStructuredExporting(m_State)) + return; + ResourceType type = IdentifyTypeByPtr(live); { diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index a70e9201d..e90968d6b 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -1290,9 +1290,9 @@ void D3D11Replay::SavePipelineState() } } -void D3D11Replay::ReadLogInitialisation(RDCFile *rdc) +void D3D11Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) { - m_pDevice->ReadLogInitialisation(rdc); + m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers); } void D3D11Replay::ReplayLog(uint32_t endEventID, ReplayLogType replayType) @@ -2110,3 +2110,16 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver) } static DriverRegistration D3D11DriverRegistration(RDC_D3D11, "D3D11", &D3D11_CreateReplayDevice); + +void D3D11_ProcessStructured(RDCFile *rdc, SDFile &output) +{ + WrappedID3D11Device device(NULL, NULL); + + device.SetStructuredExport( + rdc->GetSectionProperties(rdc->SectionIndex(SectionType::FrameCapture)).version); + device.ReadLogInitialisation(rdc, true); + + device.GetStructuredFile().swap(output); +} + +static StructuredProcessRegistration D3D11ProcessRegistration(RDC_D3D11, &D3D11_ProcessStructured); \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index 183a5b86b..b59dae3a9 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -73,7 +73,7 @@ public: void FreeTargetResource(ResourceId id); void FreeCustomShader(ResourceId id); - void ReadLogInitialisation(RDCFile *rdc); + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers); void ReplayLog(uint32_t endEventID, ReplayLogType replayType); vector GetPassEvents(uint32_t eventID); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index 891e2c294..0e0c69cc4 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -99,6 +99,8 @@ WrappedVulkan::WrappedVulkan() : m_RenderState(this, &m_CreationInfo) m_State = CaptureState::BackgroundCapturing; } + m_StructuredFile = &m_StoredStructuredData; + m_SectionVersion = VkInitParams::CurrentVersion; InitSPIRVCompiler(); @@ -1383,7 +1385,7 @@ bool WrappedVulkan::EndFrameCapture(void *dev, void *wnd) return true; } -void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc) +void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) { int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture); @@ -1400,9 +1402,11 @@ void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc) ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - // TODO make this an option passed in - ser.ConfigureStructuredExport(&GetChunkName, false); + ser.ConfigureStructuredExport(&GetChunkName, storeStructuredBuffers); + m_StructuredFile = &ser.GetStructuredFile(); + + m_StoredStructuredData.version = m_StructuredFile->version = m_SectionVersion; int chunkIdx = 0; @@ -1472,6 +1476,12 @@ void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc) } #endif + // steal the structured data for ourselves + m_StructuredFile->swap(m_StoredStructuredData); + + // and in future use this file. + m_StructuredFile = &m_StoredStructuredData; + m_FrameRecord.frameInfo.uncompressedFileSize = rdc->GetSectionProperties(sectionIdx).uncompressedSize; m_FrameRecord.frameInfo.compressedFileSize = rdc->GetSectionProperties(sectionIdx).compressedSize; @@ -1483,8 +1493,11 @@ void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc) m_FrameRecord.frameInfo.persistentSize); // ensure the capture at least created a device and fetched a queue. - RDCASSERT(m_Device != VK_NULL_HANDLE && m_Queue != VK_NULL_HANDLE && - m_InternalCmds.cmdpool != VK_NULL_HANDLE); + if(!IsStructuredExporting(m_State)) + { + RDCASSERT(m_Device != VK_NULL_HANDLE && m_Queue != VK_NULL_HANDLE && + m_InternalCmds.cmdpool != VK_NULL_HANDLE); + } } void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventID, @@ -1497,9 +1510,17 @@ void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventI ser.SetStringDatabase(&m_StringDB); ser.SetUserData(GetResourceManager()); - if(IsLoading(m_State)) + SDFile *prevFile = m_StructuredFile; + + if(IsLoading(m_State) || IsStructuredExporting(m_State)) + { ser.ConfigureStructuredExport(&GetChunkName, false); + ser.GetStructuredFile().swap(*m_StructuredFile); + + m_StructuredFile = &ser.GetStructuredFile(); + } + VulkanChunk header = ser.ReadChunk(); RDCASSERTEQUAL(header, VulkanChunk::CaptureBegin); @@ -1510,7 +1531,8 @@ void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventI ser.EndChunk(); - ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); + if(!IsStructuredExporting(m_State)) + ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); // apply initial contents here so that images are in the right layout // (not undefined) @@ -1606,6 +1628,12 @@ void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventI } } + // swap the structure back now that we've accumulated the frame as well. + if(IsLoading(m_State) || IsStructuredExporting(m_State)) + ser.GetStructuredFile().swap(*prevFile); + + m_StructuredFile = prevFile; + if(IsLoading(m_State)) { GetFrameRecord().drawcallList = m_ParentDrawcall.Bake(); @@ -1622,11 +1650,14 @@ void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventI m_ParentDrawcall.children.clear(); } - ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); + if(!IsStructuredExporting(m_State)) + { + ObjDisp(GetDev())->DeviceWaitIdle(Unwrap(GetDev())); - // destroy any events we created for waiting on - for(size_t i = 0; i < m_CleanupEvents.size(); i++) - ObjDisp(GetDev())->DestroyEvent(Unwrap(GetDev()), m_CleanupEvents[i], NULL); + // destroy any events we created for waiting on + for(size_t i = 0; i < m_CleanupEvents.size(); i++) + ObjDisp(GetDev())->DestroyEvent(Unwrap(GetDev()), m_CleanupEvents[i], NULL); + } m_CleanupEvents.clear(); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 559df59af..ef388548d 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -259,6 +259,9 @@ private: VulkanDrawcallCallback *m_DrawcallCallback; + SDFile *m_StructuredFile; + SDFile m_StoredStructuredData; + // util function to handle fetching the right eventID, calling any // aliases then calling PreDraw/PreDispatch. uint32_t HandlePreCallback(VkCommandBuffer commandBuffer, DrawFlags type = DrawFlags::Drawcall, @@ -742,10 +745,16 @@ public: ReplayStatus Initialise(VkInitParams ¶ms, uint64_t sectionVersion); uint64_t GetLogVersion() { return m_SectionVersion; } + void SetStructuredExport(uint64_t sectionVersion) + { + m_SectionVersion = sectionVersion; + m_State = CaptureState::StructuredExport; + } void Shutdown(); void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); - void ReadLogInitialisation(RDCFile *rdc); + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers); + SDFile &GetStructuredFile() { return *m_StructuredFile; } FrameRecord &GetFrameRecord() { return m_FrameRecord; } const APIEvent &GetEvent(uint32_t eventID); uint32_t GetMaxEID() { return m_Events.back().eventID; } diff --git a/renderdoc/driver/vulkan/vk_initstate.cpp b/renderdoc/driver/vulkan/vk_initstate.cpp index a02ce497d..0e934d6b7 100644 --- a/renderdoc/driver/vulkan/vk_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_initstate.cpp @@ -712,7 +712,7 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, W } else if(type == eResDeviceMemory || type == eResImage) { - VkDevice d = GetDev(); + VkDevice d = !IsStructuredExporting(m_State) ? GetDev() : VK_NULL_HANDLE; VulkanResourceManager::InitialContentData initContents = GetResourceManager()->GetInitialContents(id); @@ -797,7 +797,8 @@ bool WrappedVulkan::Serialise_InitialState(SerialiserType &ser, ResourceId id, W ser.Serialise("Contents", Contents, ContentsSize, SerialiserFlags::NoFlags); // unmap the resource we mapped before - we need to do this on read and on write. - ObjDisp(d)->UnmapMemory(Unwrap(d), Unwrap(mappedMem)); + if(!IsStructuredExporting(m_State)) + ObjDisp(d)->UnmapMemory(Unwrap(d), Unwrap(mappedMem)); // if we're handling a device memory object, we're done - we note the memory object to delete at // the end of the program, and store the buffer to copy off in Apply @@ -1023,6 +1024,9 @@ template bool WrappedVulkan::Serialise_InitialState(WriteSerialiser &ser, Resour void WrappedVulkan::Create_InitialState(ResourceId id, WrappedVkRes *live, bool hasData) { + if(IsStructuredExporting(m_State)) + return; + VkResourceType type = IdentifyTypeByPtr(live); if(type == eResDescriptorSet) diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index c44acf13c..60dd8ca5b 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -659,9 +659,9 @@ APIProperties VulkanReplay::GetAPIProperties() return ret; } -void VulkanReplay::ReadLogInitialisation(RDCFile *rdc) +void VulkanReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) { - m_pDriver->ReadLogInitialisation(rdc); + m_pDriver->ReadLogInitialisation(rdc, storeStructuredBuffers); } void VulkanReplay::ReplayLog(uint32_t endEventID, ReplayLogType replayType) @@ -5429,3 +5429,15 @@ struct VulkanDriverRegistration }; static VulkanDriverRegistration VkDriverRegistration; + +void Vulkan_ProcessStructured(RDCFile *rdc, SDFile &output) +{ + WrappedVulkan vulkan; + vulkan.SetStructuredExport( + rdc->GetSectionProperties(rdc->SectionIndex(SectionType::FrameCapture)).version); + vulkan.ReadLogInitialisation(rdc, true); + + vulkan.GetStructuredFile().swap(output); +} + +static StructuredProcessRegistration VulkanProcessRegistration(RDC_Vulkan, &Vulkan_ProcessStructured); \ No newline at end of file diff --git a/renderdoc/driver/vulkan/vk_replay.h b/renderdoc/driver/vulkan/vk_replay.h index ebcba767b..3bade8979 100644 --- a/renderdoc/driver/vulkan/vk_replay.h +++ b/renderdoc/driver/vulkan/vk_replay.h @@ -159,7 +159,7 @@ public: const VKPipe::State &GetVulkanPipelineState() { return m_VulkanPipelineState; } void FreeTargetResource(ResourceId id); - void ReadLogInitialisation(RDCFile *rdc); + void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers); void ReplayLog(uint32_t endEventID, ReplayLogType replayType); vector GetPassEvents(uint32_t eventID); diff --git a/renderdoc/driver/vulkan/vk_sparse_initstate.cpp b/renderdoc/driver/vulkan/vk_sparse_initstate.cpp index 897e3d014..e8f823ca7 100644 --- a/renderdoc/driver/vulkan/vk_sparse_initstate.cpp +++ b/renderdoc/driver/vulkan/vk_sparse_initstate.cpp @@ -478,7 +478,7 @@ template bool WrappedVulkan::Serialise_SparseBufferInitialState( SerialiserType &ser, ResourceId id, VulkanResourceManager::InitialContentData contents) { - VkDevice d = GetDev(); + VkDevice d = !IsStructuredExporting(m_State) ? GetDev() : VK_NULL_HANDLE; VkResult vkr = VK_SUCCESS; SparseBufferInitState *info = (SparseBufferInitState *)contents.blob; @@ -580,7 +580,7 @@ template bool WrappedVulkan::Serialise_SparseImageInitialState(SerialiserType &ser, ResourceId id, VulkanResourceManager::InitialContentData contents) { - VkDevice d = GetDev(); + VkDevice d = !IsStructuredExporting(m_State) ? GetDev() : VK_NULL_HANDLE; VkResult vkr = VK_SUCCESS; SparseImageInitState *info = (SparseImageInitState *)contents.blob; diff --git a/renderdoc/replay/capture_file.cpp b/renderdoc/replay/capture_file.cpp index 365980b90..1ad302808 100644 --- a/renderdoc/replay/capture_file.cpp +++ b/renderdoc/replay/capture_file.cpp @@ -131,7 +131,17 @@ public: const SDFile &GetStructuredData() { - // TODO - fetch structured data from capture on demand? + if(m_StructuredData.chunks.empty() && m_RDC && m_RDC->SectionIndex(SectionType::FrameCapture) >= 0) + { + // decompile to structured data on demand. + StructuredProcessor proc = RenderDoc::Inst().GetStructuredProcessor(m_RDC->GetDriver()); + + if(proc) + proc(m_RDC, m_StructuredData); + else + RDCERR("Can't get structured data for driver %s", m_RDC->GetDriverName().c_str()); + } + return m_StructuredData; } diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 25fa288e1..27b8b36be 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -1545,7 +1545,7 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd { m_pDevice = device; - m_pDevice->ReadLogInitialisation(rdc); + m_pDevice->ReadLogInitialisation(rdc, false); FetchPipelineState(); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 0bc3407c5..c28b11ed0 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -114,7 +114,7 @@ public: virtual FrameRecord GetFrameRecord() = 0; - virtual void ReadLogInitialisation(RDCFile *rdc) = 0; + virtual void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) = 0; virtual void ReplayLog(uint32_t endEventID, ReplayLogType replayType) = 0; virtual vector GetPassEvents(uint32_t eventID) = 0; diff --git a/renderdoccmd/renderdoccmd.cpp b/renderdoccmd/renderdoccmd.cpp index 305d7e56e..6dd5f7658 100644 --- a/renderdoccmd/renderdoccmd.cpp +++ b/renderdoccmd/renderdoccmd.cpp @@ -618,6 +618,125 @@ struct ReplayCommand : public Command } }; +struct ConvertCommand : public Command +{ + rdcarray m_Formats; + + ConvertCommand(const GlobalEnvironment &env) : Command(env) + { + ICaptureFile *tmp = RENDERDOC_OpenCaptureFile(); + + m_Formats = tmp->GetCaptureFileFormats(); + + tmp->Shutdown(); + } + + virtual void AddOptions(cmdline::parser &parser) + { + cmdline::oneof_reader formatOptions; + for(CaptureFileFormat f : m_Formats) + formatOptions.add(f.name); + + parser.add("filename", 'f', "The file to convert from.", false); + parser.add("output", 'o', "The file to convert from.", false); + parser.add("input-format", 'i', "The format of the input file.", false, "", + formatOptions); + parser.add("convert-format", 'c', "The format of the output file.", false, "", + formatOptions); + parser.add("list-formats", '\0', "print a list of target formats"); + parser.stop_at_rest(true); + } + virtual const char *Description() { return "Run internal tests such as unit tests."; } + virtual bool IsInternalOnly() { return false; } + virtual bool IsCaptureCommand() { return false; } + virtual int Execute(cmdline::parser &parser, const CaptureOptions &) + { + if(parser.exist("list-formats")) + { + std::cerr << "Available formats:" << std::endl; + for(CaptureFileFormat f : m_Formats) + std::cerr << "'" << (std::string)f.name << "': " << (std::string)f.description << std::endl; + return 0; + } + + std::string infile = parser.get("filename"); + std::string outfile = parser.get("output"); + + if(infile.empty()) + { + std::cerr << "Need an input filename." << std::endl; + std::cerr << parser.usage() << std::endl; + return 1; + } + + if(outfile.empty()) + { + std::cerr << "Need an output filename." << std::endl; + std::cerr << parser.usage() << std::endl; + return 1; + } + + std::string infmt = parser.get("input-format"); + std::string outfmt = parser.get("convert-format"); + + if(infmt.empty()) + { + // try to guess the format by looking for the extension in the filename + for(CaptureFileFormat f : m_Formats) + { + string extension = "."; + extension += f.name; + + if(infile.find(extension.c_str()) != string::npos) + { + infmt = f.name; + break; + } + } + } + + if(outfmt.empty()) + { + // try to guess the format by looking for the extension in the filename + for(CaptureFileFormat f : m_Formats) + { + string extension = "."; + extension += f.name; + + if(outfile.find(extension.c_str()) != string::npos) + { + outfmt = f.name; + break; + } + } + } + + ICaptureFile *file = RENDERDOC_OpenCaptureFile(); + + ReplayStatus st = file->OpenFile(infile.c_str(), infmt.c_str()); + + if(st != ReplayStatus::Succeeded) + { + std::cerr << "Couldn't load '" << infile << "' as '" << infmt << "': " << ToStr(st) + << std::endl; + return 1; + } + + st = file->Convert(outfile.c_str(), outfmt.c_str()); + + if(st != ReplayStatus::Succeeded) + { + std::cerr << "Couldn't convert '" << infile << "' to '" << outfile << "' as '" << outfmt + << "': " << ToStr(st) << std::endl; + return 1; + } + + std::cout << "Converted '" << infile << "' to '" << outfile << "'" << std::endl; + + return 0; + } +}; + struct TestCommand : public Command { TestCommand(const GlobalEnvironment &env) : Command(env) {} @@ -783,6 +902,7 @@ int renderdoccmd(const GlobalEnvironment &env, std::vector &argv) add_command("replay", new ReplayCommand(env)); add_command("capaltbit", new CapAltBitCommand(env)); add_command("test", new TestCommand(env)); + add_command("convert", new ConvertCommand(env)); if(argv.size() <= 1) {