diff --git a/renderdoc/core/remote_server.cpp b/renderdoc/core/remote_server.cpp index 85c7a8bc4..672ada3f6 100644 --- a/renderdoc/core/remote_server.cpp +++ b/renderdoc/core/remote_server.cpp @@ -215,525 +215,518 @@ static void ActiveRemoteClientThread(ClientThread *threadData) if(threadData->killThread) break; - Threading::Sleep(4); + // this will block until a packet comes in. + RemoteServerPacket type = reader.ReadChunk(); - if(client->IsRecvDataWaiting()) + if(reader.IsErrored() || writer.IsErrored()) + break; + + if(client == NULL) + continue; + + if(type == eRemoteServer_Ping) { - RemoteServerPacket type = reader.ReadChunk(); + reader.EndChunk(); - if(reader.IsErrored() || writer.IsErrored()) + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping); + } + else if(type == eRemoteServer_RemoteDriverList) + { + reader.EndChunk(); + + std::map drivers = RenderDoc::Inst().GetRemoteDrivers(); + uint32_t count = (uint32_t)drivers.size(); + + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList); + SERIALISE_ELEMENT(count); + + for(auto it = drivers.begin(); it != drivers.end(); ++it) + { + RDCDriver driverType = it->first; + const std::string &driverName = it->second; + + SERIALISE_ELEMENT(driverType); + SERIALISE_ELEMENT(driverName); + } + } + else if(type == eRemoteServer_HomeDir) + { + reader.EndChunk(); + + std::string home = FileIO::GetHomeFolderFilename(); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir); + SERIALISE_ELEMENT(home); + } + } + else if(type == eRemoteServer_ListDir) + { + std::string path; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } + + reader.EndChunk(); + + std::vector files = FileIO::GetFilesInDirectory(path.c_str()); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir); + SERIALISE_ELEMENT(files); + } + } + else if(type == eRemoteServer_CopyCaptureFromRemote) + { + std::string path; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } + + reader.EndChunk(); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote); + + StreamReader fileStream(FileIO::fopen(path.c_str(), "rb")); + ser.SerialiseStream(path, fileStream); + } + } + else if(type == eRemoteServer_CopyCaptureToRemote) + { + std::string path; + std::string dummy, dummy2; + FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2); + + RDCLOG("Copying file to local path '%s'.", path.c_str()); + + { + READ_DATA_SCOPE(); + + StreamWriter streamWriter(FileIO::fopen(path.c_str(), "wb"), Ownership::Stream); + + ser.SerialiseStream(path.c_str(), streamWriter, NULL); + } + + reader.EndChunk(); + + if(reader.IsErrored()) + { + FileIO::Delete(path.c_str()); + + RDCERR("Network error receiving file"); break; + } - if(client == NULL) - continue; + RDCLOG("File received."); + + tempFiles.push_back(path); - if(type == eRemoteServer_Ping) { - reader.EndChunk(); - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_Ping); + SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote); + SERIALISE_ELEMENT(path); } - else if(type == eRemoteServer_RemoteDriverList) + } + else if(type == eRemoteServer_TakeOwnershipCapture) + { + std::string path; + { - reader.EndChunk(); + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } - std::map drivers = RenderDoc::Inst().GetRemoteDrivers(); - uint32_t count = (uint32_t)drivers.size(); + reader.EndChunk(); + RDCLOG("Taking ownership of '%s'.", path.c_str()); + + tempFiles.push_back(path); + } + else if(type == eRemoteServer_ShutdownServer) + { + reader.EndChunk(); + + RDCLOG("Requested to shut down."); + + threadData->killServer = true; + threadData->killThread = true; + + { WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_RemoteDriverList); - SERIALISE_ELEMENT(count); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer); + } + } + else if(type == eRemoteServer_OpenLog) + { + std::string path; - for(auto it = drivers.begin(); it != drivers.end(); ++it) + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(path); + } + + reader.EndChunk(); + + RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL); + ReplayStatus status = ReplayStatus::InternalError; + + rdc = new RDCFile(); + rdc->Open(path.c_str()); + + if(rdc->ErrorCode() != ContainerError::NoError) + { + RDCERR("Failed to open '%s': %d", path.c_str(), rdc->ErrorCode()); + + switch(rdc->ErrorCode()) { - RDCDriver driverType = it->first; - const std::string &driverName = it->second; - - SERIALISE_ELEMENT(driverType); - SERIALISE_ELEMENT(driverName); + case ContainerError::FileNotFound: status = ReplayStatus::FileNotFound; break; + case ContainerError::FileIO: status = ReplayStatus::FileIOFailed; break; + case ContainerError::Corrupt: status = ReplayStatus::FileCorrupted; break; + case ContainerError::UnsupportedVersion: + status = ReplayStatus::FileIncompatibleVersion; + break; + default: break; } } - else if(type == eRemoteServer_HomeDir) + else { - reader.EndChunk(); - - std::string home = FileIO::GetHomeFolderFilename(); - + if(RenderDoc::Inst().HasRemoteDriver(rdc->GetDriver())) { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_HomeDir); - SERIALISE_ELEMENT(home); - } - } - else if(type == eRemoteServer_ListDir) - { - std::string path; + bool kill = false; + float progress = 0.0f; - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(path); - } + RenderDoc::Inst().SetProgressPtr(&progress); - reader.EndChunk(); - - std::vector files = FileIO::GetFilesInDirectory(path.c_str()); - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_ListDir); - SERIALISE_ELEMENT(files); - } - } - else if(type == eRemoteServer_CopyCaptureFromRemote) - { - std::string path; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(path); - } - - reader.EndChunk(); - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureFromRemote); - - StreamReader fileStream(FileIO::fopen(path.c_str(), "rb")); - ser.SerialiseStream(path, fileStream); - } - } - else if(type == eRemoteServer_CopyCaptureToRemote) - { - std::string path; - std::string dummy, dummy2; - FileIO::GetDefaultFiles("remotecopy", path, dummy, dummy2); - - RDCLOG("Copying file to local path '%s'.", path.c_str()); - - { - READ_DATA_SCOPE(); - - StreamWriter streamWriter(FileIO::fopen(path.c_str(), "wb"), Ownership::Stream); - - ser.SerialiseStream(path.c_str(), streamWriter, NULL); - } - - reader.EndChunk(); - - if(reader.IsErrored()) - { - FileIO::Delete(path.c_str()); - - RDCERR("Network error receiving file"); - break; - } - - RDCLOG("File received."); - - tempFiles.push_back(path); - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_CopyCaptureToRemote); - SERIALISE_ELEMENT(path); - } - } - else if(type == eRemoteServer_TakeOwnershipCapture) - { - std::string path; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(path); - } - - reader.EndChunk(); - - RDCLOG("Taking ownership of '%s'.", path.c_str()); - - tempFiles.push_back(path); - } - else if(type == eRemoteServer_ShutdownServer) - { - reader.EndChunk(); - - RDCLOG("Requested to shut down."); - - threadData->killServer = true; - threadData->killThread = true; - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_ShutdownServer); - } - } - else if(type == eRemoteServer_OpenLog) - { - std::string path; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(path); - } - - reader.EndChunk(); - - RDCASSERT(driver == NULL && proxy == NULL && rdc == NULL); - ReplayStatus status = ReplayStatus::InternalError; - - rdc = new RDCFile(); - rdc->Open(path.c_str()); - - if(rdc->ErrorCode() != ContainerError::NoError) - { - RDCERR("Failed to open '%s': %d", path.c_str(), rdc->ErrorCode()); - - switch(rdc->ErrorCode()) - { - case ContainerError::FileNotFound: status = ReplayStatus::FileNotFound; break; - case ContainerError::FileIO: status = ReplayStatus::FileIOFailed; break; - case ContainerError::Corrupt: status = ReplayStatus::FileCorrupted; break; - case ContainerError::UnsupportedVersion: - status = ReplayStatus::FileIncompatibleVersion; - break; - default: break; - } - } - else - { - if(RenderDoc::Inst().HasRemoteDriver(rdc->GetDriver())) - { - bool kill = false; - float progress = 0.0f; - - RenderDoc::Inst().SetProgressPtr(&progress); - - Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &kill, &progress]() { - while(!kill) - { - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpenProgress); - SERIALISE_ELEMENT(progress); - } - Threading::Sleep(100); - } - }); - - status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver); - - if(status != ReplayStatus::Succeeded || driver == NULL) + Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &kill, &progress]() { + while(!kill) { - RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str()); + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpenProgress); + SERIALISE_ELEMENT(progress); + } + Threading::Sleep(100); + } + }); + + status = RenderDoc::Inst().CreateRemoteDriver(rdc, &driver); + + if(status != ReplayStatus::Succeeded || driver == NULL) + { + RDCERR("Failed to create remote driver for driver '%s'", rdc->GetDriverName().c_str()); + } + else + { + status = driver->ReadLogInitialisation(rdc, false); + + if(status != ReplayStatus::Succeeded) + { + RDCERR("Failed to initialise remote driver."); + + driver->Shutdown(); + driver = NULL; } else { - status = driver->ReadLogInitialisation(rdc, false); + RenderDoc::Inst().SetProgressPtr(NULL); - if(status != ReplayStatus::Succeeded) - { - RDCERR("Failed to initialise remote driver."); + kill = true; + Threading::JoinThread(ticker); + Threading::CloseThread(ticker); - driver->Shutdown(); - driver = NULL; - } - else - { - RenderDoc::Inst().SetProgressPtr(NULL); - - kill = true; - Threading::JoinThread(ticker); - Threading::CloseThread(ticker); - - proxy = new ReplayProxy(reader, writer, driver); - } + proxy = new ReplayProxy(reader, writer, driver); } } - else - { - RDCERR("File needs driver for '%s' which isn't supported!", rdc->GetDriverName().c_str()); - - status = ReplayStatus::APIUnsupported; - } - } - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpened); - SERIALISE_ELEMENT(status); - } - } - else if(type == eRemoteServer_HasCallstacks) - { - reader.EndChunk(); - - bool HasCallstacks = rdc && rdc->SectionIndex(SectionType::ResolveDatabase) >= 0; - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks); - SERIALISE_ELEMENT(HasCallstacks); - } - } - else if(type == eRemoteServer_InitResolver) - { - reader.EndChunk(); - - bool success = false; - - int sectionIndex = rdc ? rdc->SectionIndex(SectionType::ResolveDatabase) : -1; - - SAFE_DELETE(resolver); - if(sectionIndex >= 0) - { - StreamReader *sectionReader = rdc->ReadSection(sectionIndex); - - std::vector buf; - buf.resize((size_t)sectionReader->GetSize()); - success = sectionReader->Read(buf.data(), sectionReader->GetSize()); - - delete sectionReader; - - if(success) - { - float progress = 0.0f; - - Threading::ThreadHandle ticker = - Threading::CreateThread([&writer, &resolver, &progress]() { - while(!resolver) - { - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_ResolverProgress); - SERIALISE_ELEMENT(progress); - } - Threading::Sleep(100); - } - }); - - resolver = Callstack::MakeResolver(buf.data(), buf.size(), &progress, NULL); - - Threading::JoinThread(ticker); - Threading::CloseThread(ticker); - } - else - { - RDCERR("Failed to read resolve database."); - } - } - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver); - SERIALISE_ELEMENT(success); - } - } - else if(type == eRemoteServer_GetResolve) - { - rdcarray StackAddresses; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(StackAddresses); - } - - reader.EndChunk(); - - rdcarray StackFrames; - - if(resolver) - { - StackFrames.reserve(StackAddresses.size()); - for(uint64_t frame : StackAddresses) - { - Callstack::AddressDetails info = resolver->GetAddr(frame); - StackFrames.push_back(info.formattedString()); - } } else { - StackFrames = {""}; - } + RDCERR("File needs driver for '%s' which isn't supported!", rdc->GetDriverName().c_str()); - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve); - SERIALISE_ELEMENT(StackFrames); + status = ReplayStatus::APIUnsupported; } } - else if(type == eRemoteServer_FindSectionByName) + { - std::string name; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(name); - } - - reader.EndChunk(); - - int index = rdc ? rdc->SectionIndex(name.c_str()) : -1; - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByName); - SERIALISE_ELEMENT(index); - } + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_LogOpened); + SERIALISE_ELEMENT(status); } - else if(type == eRemoteServer_FindSectionByType) + } + else if(type == eRemoteServer_HasCallstacks) + { + reader.EndChunk(); + + bool HasCallstacks = rdc && rdc->SectionIndex(SectionType::ResolveDatabase) >= 0; + { - SectionType sectionType; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(sectionType); - } - - reader.EndChunk(); - - int index = rdc ? rdc->SectionIndex(sectionType) : -1; - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByType); - SERIALISE_ELEMENT(index); - } + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_HasCallstacks); + SERIALISE_ELEMENT(HasCallstacks); } - else if(type == eRemoteServer_GetSectionProperties) + } + else if(type == eRemoteServer_InitResolver) + { + reader.EndChunk(); + + bool success = false; + + int sectionIndex = rdc ? rdc->SectionIndex(SectionType::ResolveDatabase) : -1; + + SAFE_DELETE(resolver); + if(sectionIndex >= 0) { - int index = -1; + StreamReader *sectionReader = rdc->ReadSection(sectionIndex); + std::vector buf; + buf.resize((size_t)sectionReader->GetSize()); + success = sectionReader->Read(buf.data(), sectionReader->GetSize()); + + delete sectionReader; + + if(success) { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(index); - } + float progress = 0.0f; - reader.EndChunk(); + Threading::ThreadHandle ticker = Threading::CreateThread([&writer, &resolver, &progress]() { + while(!resolver) + { + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ResolverProgress); + SERIALISE_ELEMENT(progress); + } + Threading::Sleep(100); + } + }); - SectionProperties props; - if(rdc && index >= 0 && index < rdc->NumSections()) - props = rdc->GetSectionProperties(index); + resolver = Callstack::MakeResolver(buf.data(), buf.size(), &progress, NULL); - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionProperties); - SERIALISE_ELEMENT(props); - } - } - else if(type == eRemoteServer_GetSectionContents) - { - int index = -1; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(index); - } - - reader.EndChunk(); - - bytebuf contents; - - if(rdc && index >= 0 && index < rdc->NumSections()) - { - StreamReader *sectionReader = rdc->ReadSection(index); - - contents.resize((size_t)sectionReader->GetSize()); - bool success = sectionReader->Read(contents.data(), sectionReader->GetSize()); - - if(!success) - contents.clear(); - - delete sectionReader; - } - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionContents); - SERIALISE_ELEMENT(contents); - } - } - else if(type == eRemoteServer_WriteSection) - { - SectionProperties props; - bytebuf contents; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(props); - SERIALISE_ELEMENT(contents); - } - - reader.EndChunk(); - - if(rdc) - { - StreamWriter *sectionWriter = rdc->WriteSection(props); - - if(sectionWriter) - { - sectionWriter->Write(contents.data(), contents.size()); - delete sectionWriter; - } - } - } - else if(type == eRemoteServer_CloseLog) - { - reader.EndChunk(); - - if(driver) - driver->Shutdown(); - driver = NULL; - - SAFE_DELETE(proxy); - SAFE_DELETE(rdc); - SAFE_DELETE(resolver); - } - else if(type == eRemoteServer_ExecuteAndInject) - { - std::string app, workingDir, cmdLine, logfile; - CaptureOptions opts; - rdcarray env; - - { - READ_DATA_SCOPE(); - SERIALISE_ELEMENT(app); - SERIALISE_ELEMENT(workingDir); - SERIALISE_ELEMENT(cmdLine); - SERIALISE_ELEMENT(opts); - SERIALISE_ELEMENT(env); - } - - reader.EndChunk(); - - uint32_t ident = 0; - - if(threadData->allowExecution) - { - ident = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(), - cmdLine.c_str(), env, "", opts, false); + Threading::JoinThread(ticker); + Threading::CloseThread(ticker); } else { - RDCWARN("Requested to execute program - disallowing based on configuration"); - } - - { - WRITE_DATA_SCOPE(); - SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject); - SERIALISE_ELEMENT(ident); + RDCERR("Failed to read resolve database."); } } - else if((int)type >= eReplayProxy_First && proxy) + { - bool ok = proxy->Tick(type); - - if(!ok) - break; - - continue; + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_InitResolver); + SERIALISE_ELEMENT(success); } + } + else if(type == eRemoteServer_GetResolve) + { + rdcarray StackAddresses; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(StackAddresses); + } + + reader.EndChunk(); + + rdcarray StackFrames; + + if(resolver) + { + StackFrames.reserve(StackAddresses.size()); + for(uint64_t frame : StackAddresses) + { + Callstack::AddressDetails info = resolver->GetAddr(frame); + StackFrames.push_back(info.formattedString()); + } + } + else + { + StackFrames = {""}; + } + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetResolve); + SERIALISE_ELEMENT(StackFrames); + } + } + else if(type == eRemoteServer_FindSectionByName) + { + std::string name; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(name); + } + + reader.EndChunk(); + + int index = rdc ? rdc->SectionIndex(name.c_str()) : -1; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByName); + SERIALISE_ELEMENT(index); + } + } + else if(type == eRemoteServer_FindSectionByType) + { + SectionType sectionType; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(sectionType); + } + + reader.EndChunk(); + + int index = rdc ? rdc->SectionIndex(sectionType) : -1; + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_FindSectionByType); + SERIALISE_ELEMENT(index); + } + } + else if(type == eRemoteServer_GetSectionProperties) + { + int index = -1; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(index); + } + + reader.EndChunk(); + + SectionProperties props; + if(rdc && index >= 0 && index < rdc->NumSections()) + props = rdc->GetSectionProperties(index); + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionProperties); + SERIALISE_ELEMENT(props); + } + } + else if(type == eRemoteServer_GetSectionContents) + { + int index = -1; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(index); + } + + reader.EndChunk(); + + bytebuf contents; + + if(rdc && index >= 0 && index < rdc->NumSections()) + { + StreamReader *sectionReader = rdc->ReadSection(index); + + contents.resize((size_t)sectionReader->GetSize()); + bool success = sectionReader->Read(contents.data(), sectionReader->GetSize()); + + if(!success) + contents.clear(); + + delete sectionReader; + } + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_GetSectionContents); + SERIALISE_ELEMENT(contents); + } + } + else if(type == eRemoteServer_WriteSection) + { + SectionProperties props; + bytebuf contents; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(props); + SERIALISE_ELEMENT(contents); + } + + reader.EndChunk(); + + if(rdc) + { + StreamWriter *sectionWriter = rdc->WriteSection(props); + + if(sectionWriter) + { + sectionWriter->Write(contents.data(), contents.size()); + delete sectionWriter; + } + } + } + else if(type == eRemoteServer_CloseLog) + { + reader.EndChunk(); + + if(driver) + driver->Shutdown(); + driver = NULL; + + SAFE_DELETE(proxy); + SAFE_DELETE(rdc); + SAFE_DELETE(resolver); + } + else if(type == eRemoteServer_ExecuteAndInject) + { + std::string app, workingDir, cmdLine, logfile; + CaptureOptions opts; + rdcarray env; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(app); + SERIALISE_ELEMENT(workingDir); + SERIALISE_ELEMENT(cmdLine); + SERIALISE_ELEMENT(opts); + SERIALISE_ELEMENT(env); + } + + reader.EndChunk(); + + uint32_t ident = 0; + + if(threadData->allowExecution) + { + ident = Process::LaunchAndInjectIntoProcess(app.c_str(), workingDir.c_str(), + cmdLine.c_str(), env, "", opts, false); + } + else + { + RDCWARN("Requested to execute program - disallowing based on configuration"); + } + + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(eRemoteServer_ExecuteAndInject); + SERIALISE_ELEMENT(ident); + } + } + else if((int)type >= eReplayProxy_First && proxy) + { + bool ok = proxy->Tick(type); + + if(!ok) + break; continue; } diff --git a/renderdoc/core/target_control.cpp b/renderdoc/core/target_control.cpp index 3c0006183..673801af7 100644 --- a/renderdoc/core/target_control.cpp +++ b/renderdoc/core/target_control.cpp @@ -195,7 +195,7 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) continue; } - if(client->IsRecvDataWaiting()) + if(client->IsRecvDataWaiting() || !reader.GetReader()->AtEnd()) { PacketType type = reader.ReadChunk(); @@ -533,7 +533,7 @@ public: return msg; } - if(!m_Socket->IsRecvDataWaiting()) + if(!m_Socket->IsRecvDataWaiting() && reader.GetReader()->AtEnd()) { if(!m_Socket->Connected()) { diff --git a/renderdoc/serialise/serialiser.cpp b/renderdoc/serialise/serialiser.cpp index 947aacad0..f8f8556cb 100644 --- a/renderdoc/serialise/serialiser.cpp +++ b/renderdoc/serialise/serialiser.cpp @@ -404,6 +404,8 @@ void Serialiser::EndChunk() m_Write->AlignTo(); m_ChunkMetadata = SDChunkMetaData(); + + m_Write->Flush(); } template <> diff --git a/renderdoc/serialise/streamio.cpp b/renderdoc/serialise/streamio.cpp index b95132647..300890888 100644 --- a/renderdoc/serialise/streamio.cpp +++ b/renderdoc/serialise/streamio.cpp @@ -24,6 +24,7 @@ #include "streamio.h" #include +#include "common/timing.h" Compressor::~Compressor() { @@ -76,11 +77,12 @@ StreamReader::StreamReader(Network::Socket *sock, Ownership own) { m_Sock = sock; - m_InputSize = m_BufferSize = initialBufferSize; + m_BufferSize = initialBufferSize; m_BufferBase = AllocAlignedBuffer(m_BufferSize); - // place head at the *end* of the buffer, because for sockets we pretend the buffer is constantly - // exhausted, and just do a read of the minimum number of bytes each time to satisfy each read - m_BufferHead = m_BufferBase + m_BufferSize; + m_BufferHead = m_BufferBase; + + // for sockets we use m_InputSize to indicate how much data has been read into the buffer. + m_InputSize = 0; m_Ownership = own; } @@ -189,25 +191,7 @@ void StreamReader::SetOffset(uint64_t offs) bool StreamReader::Reserve(uint64_t numBytes) { - if(m_Sock) - { - // if we're reading more bytes than our buffer size, resize up - if(numBytes > m_BufferSize) - { - FreeAlignedBuffer(m_BufferBase); - m_InputSize = m_BufferSize = AlignUp(numBytes, 256ULL); - m_BufferBase = AllocAlignedBuffer(m_BufferSize); - m_BufferHead = m_BufferBase + m_BufferSize; - } - - m_ReadOffset += numBytes; - - // read into the end of the buffer, so that the subsequent read re-exhausts the buffer - m_BufferHead = m_BufferBase + m_BufferSize - numBytes; - return ReadFromExternal(m_BufferSize - numBytes, numBytes); - } - - RDCASSERT(m_File || m_Decompressor); + RDCASSERT(m_Sock || m_File || m_Decompressor); // store old buffer and the read data, so we can move it into the new buffer byte *oldBuffer = m_BufferBase; @@ -218,6 +202,9 @@ bool StreamReader::Reserve(uint64_t numBytes) byte *currentData = m_BufferHead - backwardsWindow; uint64_t currentDataSize = m_BufferSize - (m_BufferHead - m_BufferBase) + backwardsWindow; + if(m_Sock) + currentDataSize = m_InputSize - (m_BufferHead - m_BufferBase) + backwardsWindow; + uint64_t BufferOffset = m_BufferHead - m_BufferBase; // if we are reading more than our current buffer size, expand the buffer size @@ -243,11 +230,21 @@ bool StreamReader::Reserve(uint64_t numBytes) m_BufferHead = m_BufferBase + BufferOffset; } + if(m_Sock) + m_InputSize = currentDataSize; + // if there's anything left of the file to read in, do so now bool ret = false; - ret = ReadFromExternal(currentDataSize, RDCMIN(m_BufferSize - currentDataSize, - m_InputSize - m_ReadOffset - currentDataSize)); + uint64_t readSize = + RDCMIN(m_BufferSize - currentDataSize, m_InputSize - m_ReadOffset - currentDataSize); + + // we'll read as much as possible anyway using m_BufferSize, but we need to know how much we + // *must* read. + if(m_Sock) + readSize = numBytes - Available(); + + ret = ReadFromExternal(currentDataSize, readSize); if(oldBuffer != m_BufferBase && m_BufferBase) FreeAlignedBuffer(oldBuffer); @@ -276,7 +273,24 @@ bool StreamReader::ReadFromExternal(uint64_t bufferOffs, uint64_t length) } else { - success = m_Sock->RecvDataBlocking(m_BufferBase + bufferOffs, (uint32_t)length); + // first get the required data blocking (this will sleep the thread until it comes in). + byte *readDest = m_BufferBase + bufferOffs; + + success = m_Sock->RecvDataBlocking(readDest, (uint32_t)length); + + if(success) + { + m_InputSize += length; + readDest += length; + + uint32_t bufSize = uint32_t(m_BufferSize - m_InputSize); + + // now read more, as much as possible, to try and batch future reads + success = m_Sock->RecvDataNonBlocking(readDest, bufSize); + + if(success) + m_InputSize += bufSize; + } } } else @@ -344,7 +358,8 @@ StreamWriter::StreamWriter(StreamInvalidType) StreamWriter::StreamWriter(Network::Socket *sock, Ownership own) { - m_BufferBase = m_BufferHead = m_BufferEnd = NULL; + m_BufferBase = m_BufferHead = AllocAlignedBuffer(initialBufferSize); + m_BufferEnd = m_BufferBase + initialBufferSize; m_Sock = sock; @@ -389,6 +404,56 @@ StreamWriter::~StreamWriter() } } +bool StreamWriter::SendSocketData(const void *data, uint64_t numBytes) +{ + // try to coalesce small writes without doing blocking sends, at least until we're flushed. + // if the buffer is already full, flush it. + if(m_BufferHead + numBytes >= m_BufferEnd) + { + bool success = FlushSocketData(); + if(!success) + { + HandleError(); + return false; + } + } + + // if it's larger than our buffer (even after flushing) just write directly + if(m_BufferHead + numBytes >= m_BufferEnd) + { + bool success = m_Sock->SendDataBlocking(data, (uint32_t)numBytes); + if(!success) + { + HandleError(); + return false; + } + } + else + { + // otherwise, write it into the in-memory buffer + memcpy(m_BufferHead, data, (size_t)numBytes); + m_BufferHead += numBytes; + } + + return true; +} + +bool StreamWriter::FlushSocketData() +{ + // send out what we have buffered up + bool success = m_Sock->SendDataBlocking(m_BufferBase, uint32_t(m_BufferHead - m_BufferBase)); + if(!success) + { + HandleError(); + return false; + } + + // reset buffer to the start + m_BufferHead = m_BufferBase; + + return true; +} + void StreamWriter::HandleError() { if(m_File) diff --git a/renderdoc/serialise/streamio.h b/renderdoc/serialise/streamio.h index 13c73ee9a..571a16805 100644 --- a/renderdoc/serialise/streamio.h +++ b/renderdoc/serialise/streamio.h @@ -91,7 +91,12 @@ public: inline uint64_t GetOffset() { return m_BufferHead - m_BufferBase + m_ReadOffset; } inline uint64_t GetSize() { return m_InputSize; } - inline bool AtEnd() { return GetOffset() >= GetSize(); } + inline bool AtEnd() + { + if(m_Sock) + return Available() == 0; + return GetOffset() >= GetSize(); + } template bool AlignTo() { @@ -189,7 +194,7 @@ private: inline uint64_t Available() { if(m_Sock) - return 0; + return m_InputSize - (m_BufferHead - m_BufferBase); return m_BufferSize - (m_BufferHead - m_BufferBase); } bool Reserve(uint64_t numBytes); @@ -327,14 +332,7 @@ public: } else if(m_Sock) { - bool success = m_Sock->SendDataBlocking(data, (uint32_t)numBytes); - if(!success) - { - HandleError(); - return false; - } - - return true; + return SendSocketData(data, numBytes); } else { @@ -396,6 +394,18 @@ public: return false; } + bool Flush() + { + if(m_Compressor) + return true; + else if(m_File) + return FileIO::fflush(m_File); + else if(m_Sock) + return FlushSocketData(); + + return true; + } + bool Finish() { if(m_Compressor) @@ -437,6 +447,9 @@ private: void HandleError(); + bool SendSocketData(const void *data, uint64_t numBytes); + bool FlushSocketData(); + // used for aligned writes static const byte empty[128];