DspChunk DspRate::ProcessEosChunk(soxr_t soxr, DspChunk& chunk) { assert(soxr); DspChunk output; if (!chunk.IsEmpty()) output = ProcessChunk(soxr, chunk); for (;;) { DspChunk tailChunk(DspFormat::Float, m_channels, m_outputRate, m_outputRate); size_t inputDone = 0; size_t outputDo = tailChunk.GetFrameCount(); size_t outputDone = 0; soxr_process(soxr, nullptr, 0, &inputDone, tailChunk.GetData(), outputDo, &outputDone); tailChunk.ShrinkTail(outputDone); DspChunk::MergeChunks(output, tailChunk); if (outputDone < outputDo) break; } return output; }
void DspRate::Process(DspChunk& chunk) { soxr_t soxr = GetBackend(); if (!soxr || chunk.IsEmpty()) return; if (m_state == State::Variable && !m_inStateTransition && m_variableDelay > 0) { uint64_t inputPosition = llMulDiv(m_variableOutputFrames, m_inputRate, m_outputRate, 0); int64_t adjustedFrames = inputPosition + m_variableDelay - m_variableInputFrames; REFERENCE_TIME adjustTime = m_adjustTime - FramesToTimeLong(adjustedFrames, m_inputRate); double ratio = (double)m_inputRate * 4 / (m_outputRate * (4 + (double)adjustTime / OneSecond)); // TODO: decrease jitter soxr_set_io_ratio(m_soxrv, ratio, m_outputRate / 1000); } DspChunk output = ProcessChunk(soxr, chunk); if (m_state == State::Variable) { m_variableInputFrames += chunk.GetFrameCount(); m_variableOutputFrames += output.GetFrameCount(); // soxr_delay() method is not implemented for variable rate conversion yet, // but the delay stays more or less constant and we can calculate it in a roundabout way. if (m_variableDelay == 0 && m_variableOutputFrames > 0) { uint64_t inputPosition = llMulDiv(m_variableOutputFrames, m_inputRate, m_outputRate, 0); m_variableDelay = m_variableInputFrames - inputPosition; } } FinishStateTransition(output, chunk, false); chunk = std::move(output); }
void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) { m_State = readType; m_DoStateVerify = true; D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); RDCASSERT(header == CONTEXT_CAPTURE_HEADER); ResourceId id; m_pSerialiser->Serialise("context", id); WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id); RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this); Serialise_BeginCaptureFrame(!partial); m_pSerialiser->PopContext(NULL, header); m_CurEvents.clear(); if(m_State == EXECUTING) { FetchAPIEvent ev = GetEvent(startEventID); m_CurEventID = ev.eventID; m_pSerialiser->SetOffset(ev.fileOffset); } else if(m_State == READING) { m_CurEventID = 1; } if(m_State == EXECUTING) { ClearMaps(); for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++) { WrappedID3D11DeviceContext *defcontext = m_pDevice->GetDeferredContext(i); defcontext->ClearMaps(); } } m_pDevice->GetResourceManager()->MarkInFrame(true); uint64_t startOffset = m_pSerialiser->GetOffset(); while(1) { if(m_State == EXECUTING && m_CurEventID > endEventID) { // we can just break out if we've done all the events desired. break; } uint64_t offset = m_pSerialiser->GetOffset(); D3D11ChunkType chunktype = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); ProcessChunk(offset, chunktype, false); RenderDoc::Inst().SetProgress(FrameEventsRead, float(offset - startOffset)/float(m_pSerialiser->GetSize())); // for now just abort after capture scope. Really we'd need to support multiple frames // but for now this will do. if(chunktype == CONTEXT_CAPTURE_FOOTER) break; m_CurEventID++; } if(m_State == READING) { m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); m_pDevice->GetFrameRecord().back().frameInfo.debugMessages = m_pDevice->GetDebugMessages(); int initialSkips = 0; for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; // it's easier to remove duplicate usages here than check it as we go. // this means if textures are bound in multiple places in the same draw // we don't have duplicate uses for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it) { vector<EventUsage> &v = it->second; std::sort(v.begin(), v.end()); v.erase( std::unique(v.begin(), v.end()), v.end() ); #if 0 ResourceId resid = m_pDevice->GetResourceManager()->GetOriginalID(it->first); if(m_pDevice->GetResourceManager()->GetInitialContents(resid).resource == NULL) continue; // code disabled for now as skipping these initial states // doesn't seem to produce any measurable improvement in any case // I've checked RDCDEBUG("Resource %llu", resid); if(v.empty()) { RDCDEBUG("Never used!"); initialSkips++; } else { bool written = false; for(auto usit = v.begin(); usit != v.end(); ++usit) { ResourceUsage u = usit->usage; if(u == eUsage_SO || (u >= eUsage_VS_RWResource && u <= eUsage_CS_RWResource) || u == eUsage_DepthStencilTarget || u == eUsage_ColourTarget) { written = true; break; } } if(written) { RDCDEBUG("Written in frame - needs initial state"); } else { RDCDEBUG("Never written to in the frame"); initialSkips++; } } #endif } //RDCDEBUG("Can skip %d initial states.", initialSkips); } m_pDevice->GetResourceManager()->MarkInFrame(false); m_State = READING; m_DoStateVerify = false; }
void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) { m_State = readType; D3D12ChunkType header = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false); RDCASSERTEQUAL(header, CONTEXT_CAPTURE_HEADER); m_pDevice->Serialise_BeginCaptureFrame(!partial); if(readType == READING) { GetResourceManager()->ApplyInitialContents(); m_pDevice->ExecuteLists(); m_pDevice->FlushLists(); } m_pSerialiser->PopContext(header); m_Cmd.m_RootEvents.clear(); if(m_State == EXECUTING) { FetchAPIEvent ev = GetEvent(startEventID); m_Cmd.m_RootEventID = ev.eventID; // if not partial, we need to be sure to replay // past the command list records, so can't // skip to the file offset of the first event if(partial) m_pSerialiser->SetOffset(ev.fileOffset); m_Cmd.m_FirstEventID = startEventID; m_Cmd.m_LastEventID = endEventID; } else if(m_State == READING) { m_Cmd.m_RootEventID = 1; m_Cmd.m_RootDrawcallID = 1; m_Cmd.m_FirstEventID = 0; m_Cmd.m_LastEventID = ~0U; } for(;;) { if(m_State == EXECUTING && m_Cmd.m_RootEventID > endEventID) { // we can just break out if we've done all the events desired. // note that the command list events aren't 'real' and we just blaze through them break; } uint64_t offset = m_pSerialiser->GetOffset(); D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false); m_Cmd.m_LastCmdListID = ResourceId(); ProcessChunk(offset, context); RenderDoc::Inst().SetProgress(FileInitialRead, float(offset) / float(m_pSerialiser->GetSize())); // for now just abort after capture scope. Really we'd need to support multiple frames // but for now this will do. if(context == CONTEXT_CAPTURE_FOOTER) break; // break out if we were only executing one event if(m_State == EXECUTING && startEventID == endEventID) break; // increment root event ID either if we didn't just replay a cmd // buffer event, OR if we are doing a frame sub-section replay, // in which case it's up to the calling code to make sure we only // replay inside a command list (if we crossed command list // boundaries, the event IDs would no longer match up). if(m_Cmd.m_LastCmdListID == ResourceId() || startEventID > 1) { m_Cmd.m_RootEventID++; if(startEventID > 1) m_pSerialiser->SetOffset(GetEvent(m_Cmd.m_RootEventID).fileOffset); } else { m_Cmd.m_BakedCmdListInfo[m_Cmd.m_LastCmdListID].curEventID++; } } if(m_State == READING) { struct SortEID { bool operator()(const FetchAPIEvent &a, const FetchAPIEvent &b) { return a.eventID < b.eventID; } }; std::sort(m_Cmd.m_Events.begin(), m_Cmd.m_Events.end(), SortEID()); } for(int p = 0; p < D3D12CommandData::ePartialNum; p++) SAFE_RELEASE(m_Cmd.m_Partial[p].resultPartialCmdList); for(auto it = m_Cmd.m_RerecordCmds.begin(); it != m_Cmd.m_RerecordCmds.end(); ++it) SAFE_RELEASE(it->second); m_Cmd.m_RerecordCmds.clear(); m_State = READING; }
void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) { m_State = readType; m_DoStateVerify = true; D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); RDCASSERT(header == CONTEXT_CAPTURE_HEADER); ResourceId id; m_pSerialiser->Serialise("context", id); WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id); RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this); Serialise_BeginCaptureFrame(!partial); m_pSerialiser->PopContext(NULL, header); m_CurEvents.clear(); if(m_State == EXECUTING) { FetchAPIEvent ev = GetEvent(startEventID); m_CurEventID = ev.eventID; m_pSerialiser->SetOffset(ev.fileOffset); } else if(m_State == READING) { m_CurEventID = 1; } if(m_State == EXECUTING) { ClearMaps(); for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++) { WrappedID3D11DeviceContext *context = m_pDevice->GetDeferredContext(i); context->ClearMaps(); } } m_pDevice->GetResourceManager()->MarkInFrame(true); while(1) { if(m_State == EXECUTING && m_CurEventID > endEventID) { // we can just break out if we've done all the events desired. break; } uint64_t offset = m_pSerialiser->GetOffset(); D3D11ChunkType context = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); ProcessChunk(offset, context, false); RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize())); // for now just abort after capture scope. Really we'd need to support multiple frames // but for now this will do. if(context == CONTEXT_CAPTURE_FOOTER) break; m_CurEventID++; } if(m_State == READING) { m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake(); m_ParentDrawcall.children.clear(); int initialSkips = 0; for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it) m_ResourceUses[it->first]; for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it) { ResourceId id = m_pDevice->GetResourceManager()->GetOriginalID(it->first); if(m_pDevice->GetResourceManager()->GetInitialContents(id) == NULL) continue; RDCDEBUG("Resource %llu", id); if(it->second.empty()) { RDCDEBUG("Never used!"); initialSkips++; } else { bool written = false; for(auto usit = it->second.begin(); usit != it->second.end(); ++usit) { ResourceUsage u = usit->usage; if(u == eUsage_SO || u == eUsage_CS_UAV || u == eUsage_PS_UAV || u == eUsage_OM_DSV || u == eUsage_OM_RTV) { written = true; break; } } if(written) { RDCDEBUG("Written in frame - needs initial state"); } else { RDCDEBUG("Never written to in the frame"); initialSkips++; } } } RDCDEBUG("Can skip %d initial states.", initialSkips); } m_pDevice->GetResourceManager()->MarkInFrame(false); m_State = READING; m_DoStateVerify = false; }
void DspRate::FinishStateTransition(DspChunk& processedChunk, DspChunk& unprocessedChunk, bool eos) { if (m_inStateTransition) { assert(m_state == State::Variable); DspChunk::ToFloat(processedChunk); DspChunk::ToFloat(unprocessedChunk); auto& first = m_transitionChunks.first; auto& second = m_transitionChunks.second; DspChunk::MergeChunks(first, processedChunk); assert(processedChunk.IsEmpty()); if (m_soxrc) { // Transitioning from constant rate conversion to variable. if (!m_transitionCorrelation.first) m_transitionCorrelation = {true, (size_t)std::round(soxr_delay(m_soxrc))}; if (m_transitionCorrelation.second > 0) { DspChunk::MergeChunks(second, eos ? ProcessEosChunk(m_soxrc, unprocessedChunk) : ProcessChunk(m_soxrc, unprocessedChunk)); } else { // Nothing to flush from constant rate conversion buffer. m_inStateTransition = false; } } else { // Transitioning from pass-through to variable rate conversion. m_transitionCorrelation = {}; DspChunk::MergeChunks(second, unprocessedChunk); } // Cross-fade. if (m_inStateTransition) { const size_t transitionFrames = m_outputRate / 1000; // 1ms if (first.GetFrameCount() >= transitionFrames && second.GetFrameCount() >= m_transitionCorrelation.second + transitionFrames) { second.ShrinkHead(second.GetFrameCount() - m_transitionCorrelation.second); Crossfade(first, second, transitionFrames); processedChunk = std::move(first); m_inStateTransition = false; } else if (eos) { processedChunk = std::move(second); m_inStateTransition = false; } } if (!m_inStateTransition) { m_transitionCorrelation = {}; m_transitionChunks = {}; DestroyBackend(m_soxrc); } } unprocessedChunk = {}; }
DWORD ReadHeader(FILE *f, int depth, DWORD max_size) { struct { DWORD type; DWORD size; } header; DWORD size = 0; if (fread(&header, 1, sizeof(header), f) == sizeof(header)) { size = header.size & 0x7FFFFFFF; char *chunk_type = lookup(header.type, size); indent = depth * 3; fprintf(outf, "%s%08X %s [%d]\n", Indent(), header.type, chunk_type, size); indent = depth * 3 + 9; if (size > 4*1024*1024) { printf("*ERROR* header is exceedingly big!\n"); } else if (depth > 10) { printf("*ERROR* nested too deep!\n"); } else if (size + sizeof(header) > max_size) { printf("*ERROR* structure size exceeds container!\n"); } else { if (IsNested(header.type)) { long remaining = size; while (remaining > 0) { DWORD bytes_read = ReadHeader(f, depth + 1, remaining) + sizeof(header); remaining -= bytes_read; } } else { BYTE *data = new BYTE[size]; fread(data, size, 1, f); ProcessChunk(header.type, data, size); delete data; } } } else { if (depth > 0) { printf("*ERROR* fread failed\n"); } } return (size); }