diff --git a/renderdoc/core/target_control.cpp b/renderdoc/core/target_control.cpp index 62a11ea18..c83e6d097 100644 --- a/renderdoc/core/target_control.cpp +++ b/renderdoc/core/target_control.cpp @@ -30,9 +30,9 @@ #include "os/os_specific.h" #include "serialise/serialiser.h" -enum PacketType +enum PacketType : uint32_t { - ePacket_Noop, + ePacket_Noop = 1, ePacket_Handshake, ePacket_Busy, ePacket_NewCapture, @@ -44,25 +44,55 @@ enum PacketType ePacket_NewChild, }; +DECLARE_REFLECTION_ENUM(PacketType); + +template <> +std::string DoStringise(const PacketType &el) +{ + BEGIN_ENUM_STRINGISE(PacketType); + { + STRINGISE_ENUM_NAMED(ePacket_Noop, "No-op"); + STRINGISE_ENUM_NAMED(ePacket_Handshake, "Handshake"); + STRINGISE_ENUM_NAMED(ePacket_Busy, "Busy"); + STRINGISE_ENUM_NAMED(ePacket_NewCapture, "New Capture"); + STRINGISE_ENUM_NAMED(ePacket_RegisterAPI, "Register API"); + STRINGISE_ENUM_NAMED(ePacket_TriggerCapture, "Trigger Capture"); + STRINGISE_ENUM_NAMED(ePacket_CopyCapture, "Copy Capture"); + STRINGISE_ENUM_NAMED(ePacket_DeleteCapture, "Delete Capture"); + STRINGISE_ENUM_NAMED(ePacket_QueueCapture, "Queue Capture"); + STRINGISE_ENUM_NAMED(ePacket_NewChild, "New Child"); + } + END_ENUM_STRINGISE(); +} + +#define WRITE_DATA_SCOPE() WriteSerialiser &ser = writer; +#define READ_DATA_SCOPE() ReadSerialiser &ser = reader; + void RenderDoc::TargetControlClientThread(Network::Socket *client) { Threading::KeepModuleAlive(); - Serialiser ser("", Serialiser::WRITING, false); + WriteSerialiser writer(new StreamWriter(client, Ownership::Nothing), Ownership::Stream); + ReadSerialiser reader(new StreamReader(client, Ownership::Nothing), Ownership::Stream); - string api = ""; + writer.SetStreamingMode(true); + + std::string api = ""; RDCDriver driver; RenderDoc::Inst().GetCurrentDriver(driver, api); - ser.Rewind(); - - string target = RenderDoc::Inst().GetCurrentTarget(); - ser.Serialise("", target); - ser.Serialise("", api); + std::string target = RenderDoc::Inst().GetCurrentTarget(); uint32_t mypid = Process::GetCurrentPID(); - ser.Serialise("", mypid); - if(!SendPacket(client, ePacket_Handshake, ser)) + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_Handshake); + SERIALISE_ELEMENT(target); + SERIALISE_ELEMENT(api); + SERIALISE_ELEMENT(mypid); + } + + if(writer.IsErrored()) { SAFE_DELETE(client); @@ -79,8 +109,8 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) const int ticktime = 10; // tick every 10ms int curtime = 0; - vector captures; - vector > children; + std::vector captures; + std::vector > children; while(client) { @@ -90,26 +120,24 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) break; } - ser.Rewind(); - Threading::Sleep(ticktime); curtime += ticktime; - PacketType packetType = ePacket_Noop; - - string curapi; + std::string curapi; RenderDoc::Inst().GetCurrentDriver(driver, curapi); - vector caps = RenderDoc::Inst().GetCaptures(); - vector > childprocs = RenderDoc::Inst().GetChildProcesses(); + std::vector caps = RenderDoc::Inst().GetCaptures(); + std::vector > childprocs = RenderDoc::Inst().GetChildProcesses(); if(curapi != api) { api = curapi; - ser.Serialise("", api); - - packetType = ePacket_RegisterAPI; + WRITE_DATA_SCOPE(); + { + SCOPED_SERIALISE_CHUNK(ePacket_RegisterAPI); + SERIALISE_ELEMENT(api); + } } else if(caps.size() != captures.size()) { @@ -117,14 +145,8 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) captures.push_back(caps[idx]); - packetType = ePacket_NewCapture; - std::string path = FileIO::GetFullPathname(captures.back().path); - ser.Serialise("", idx); - ser.Serialise("", captures.back().timestamp); - ser.Serialise("", path); - bytebuf buf; ICaptureFile *file = RENDERDOC_OpenCaptureFile(captures.back().path.c_str()); @@ -134,12 +156,14 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) } file->Shutdown(); - int32_t thumblen = buf.count(); - ser.Serialise("", thumblen); - - byte *data = buf.data(); - size_t sz = buf.size(); - ser.SerialiseBuffer("", data, sz); + WRITE_DATA_SCOPE(); + { + SCOPED_SERIALISE_CHUNK(ePacket_NewCapture); + SERIALISE_ELEMENT(idx); + SERIALISE_ELEMENT(captures.back().timestamp); + SERIALISE_ELEMENT(path); + SERIALISE_ELEMENT(buf); + } } else if(childprocs.size() != children.size()) { @@ -147,91 +171,95 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client) children.push_back(childprocs[idx]); - packetType = ePacket_NewChild; - - ser.Serialise("", children.back().first); - ser.Serialise("", children.back().second); - } - - if(curtime < pingtime && packetType == ePacket_Noop) - { - if(client->IsRecvDataWaiting()) + WRITE_DATA_SCOPE(); { - PacketType type; - Serialiser *recvser = NULL; - - if(!RecvPacket(client, type, &recvser)) - SAFE_DELETE(client); - - if(client == NULL) - { - SAFE_DELETE(recvser); - continue; - } - else if(type == ePacket_TriggerCapture) - { - uint32_t numFrames = 0; - recvser->Serialise("", numFrames); - - RenderDoc::Inst().TriggerCapture(numFrames); - } - else if(type == ePacket_QueueCapture) - { - uint32_t frameNum = 0; - recvser->Serialise("", frameNum); - - RenderDoc::Inst().QueueCapture(frameNum); - } - else if(type == ePacket_DeleteCapture) - { - uint32_t id = 0; - recvser->Serialise("", id); - - // this means it will be deleted on shutdown - RenderDoc::Inst().MarkCaptureRetrieved(id); - } - else if(type == ePacket_CopyCapture) - { - caps = RenderDoc::Inst().GetCaptures(); - - uint32_t id = 0; - recvser->Serialise("", id); - - if(id < caps.size()) - { - ser.Serialise("", id); - - if(!SendPacket(client, ePacket_CopyCapture, ser)) - { - SAFE_DELETE(client); - continue; - } - - ser.Rewind(); - - if(!SendChunkedFile(client, ePacket_CopyCapture, caps[id].path.c_str(), ser, NULL)) - { - SAFE_DELETE(client); - continue; - } - - RenderDoc::Inst().MarkCaptureRetrieved(id); - } - } - - SAFE_DELETE(recvser); + SCOPED_SERIALISE_CHUNK(ePacket_NewChild); + SERIALISE_ELEMENT(children.back().first); + SERIALISE_ELEMENT(children.back().second); } - - continue; } - curtime = 0; + if(curtime > pingtime) + { + WRITE_DATA_SCOPE(); + { + SCOPED_SERIALISE_CHUNK(ePacket_Noop); + } + curtime = 0; + } - if(!SendPacket(client, packetType, ser)) + if(writer.IsErrored()) { SAFE_DELETE(client); continue; } + + if(client->IsRecvDataWaiting()) + { + PacketType type = (PacketType)reader.BeginChunk(0); + + if(type == ePacket_TriggerCapture) + { + uint32_t numFrames; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(numFrames); + + RenderDoc::Inst().TriggerCapture(numFrames); + } + else if(type == ePacket_QueueCapture) + { + uint32_t frameNum; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(frameNum); + + RenderDoc::Inst().QueueCapture(frameNum); + } + else if(type == ePacket_DeleteCapture) + { + uint32_t id; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(id); + + // this means it will be deleted on shutdown + RenderDoc::Inst().MarkCaptureRetrieved(id); + } + else if(type == ePacket_CopyCapture) + { + caps = RenderDoc::Inst().GetCaptures(); + + uint32_t id; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(id); + } + + if(id < caps.size()) + { + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_CopyCapture); + SERIALISE_ELEMENT(id); + + std::string filename = caps[id].path; + + StreamReader fileStream(FileIO::fopen(filename.c_str(), "rb")); + ser.SerialiseStream(filename, fileStream); + + if(fileStream.IsErrored() || ser.IsErrored()) + SAFE_DELETE(client); + else + RenderDoc::Inst().MarkCaptureRetrieved(id); + } + } + + reader.EndChunk(); + + if(reader.IsErrored()) + SAFE_DELETE(client); + } } // give up our connection @@ -273,32 +301,26 @@ void RenderDoc::TargetControlServerThread(Network::Socket *sock) continue; } - string existingClient; - string newClient; + std::string existingClient; + std::string newClient; bool kick = false; // receive handshake from client and get its name { - PacketType type; - Serialiser *ser = NULL; - if(!RecvPacket(client, type, &ser)) - { - SAFE_DELETE(ser); - SAFE_DELETE(client); - continue; - } + ReadSerialiser ser(new StreamReader(client, Ownership::Nothing), Ownership::Stream); + + PacketType type = (PacketType)ser.BeginChunk(0); if(type != ePacket_Handshake) { - SAFE_DELETE(ser); SAFE_DELETE(client); continue; } - ser->SerialiseString("", newClient); - ser->Serialise("", kick); + SERIALISE_ELEMENT(newClient); + SERIALISE_ELEMENT(kick); - SAFE_DELETE(ser); + ser.EndChunk(); if(newClient.empty()) { @@ -340,21 +362,23 @@ void RenderDoc::TargetControlServerThread(Network::Socket *sock) { // if we've been asked to kick the existing connection off // reject this connection and tell them who is busy - Serialiser ser("", Serialiser::WRITING, false); + WriteSerialiser ser(new StreamWriter(client, Ownership::Nothing), Ownership::Stream); - string api = ""; + ser.SetStreamingMode(true); + + std::string api = ""; RDCDriver driver; RenderDoc::Inst().GetCurrentDriver(driver, api); - string target = RenderDoc::Inst().GetCurrentTarget(); - ser.Serialise("", target); - ser.Serialise("", api); - - ser.SerialiseString("", RenderDoc::Inst().m_SingleClientName); + std::string target = RenderDoc::Inst().GetCurrentTarget(); + { + SCOPED_SERIALISE_CHUNK(ePacket_Busy); + SERIALISE_ELEMENT(target); + SERIALISE_ELEMENT(api); + SERIALISE_ELEMENT(RenderDoc::Inst().m_SingleClientName); + } // don't care about errors, we're going to close the connection either way - SendPacket(client, ePacket_Busy, ser); - SAFE_DELETE(client); } } @@ -372,54 +396,69 @@ void RenderDoc::TargetControlServerThread(Network::Socket *sock) struct TargetControl : public ITargetControl { public: - TargetControl(Network::Socket *sock, string clientName, bool forceConnection) : m_Socket(sock) + TargetControl(Network::Socket *sock, std::string clientName, bool forceConnection) + : m_Socket(sock), + reader(new StreamReader(sock, Ownership::Nothing), Ownership::Stream), + writer(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream) { - PacketType type; - vector payload; + std::vector payload; + + writer.SetStreamingMode(true); m_PID = 0; { - Serialiser ser("", Serialiser::WRITING, false); + WRITE_DATA_SCOPE(); - ser.SerialiseString("", clientName); - ser.Serialise("", forceConnection); + { + SCOPED_SERIALISE_CHUNK(ePacket_Handshake); + SERIALISE_ELEMENT(clientName); + SERIALISE_ELEMENT(forceConnection); + } - if(!SendPacket(m_Socket, ePacket_Handshake, ser)) + if(writer.IsErrored()) { SAFE_DELETE(m_Socket); return; } } - Serialiser *ser = NULL; - GetPacket(type, ser); + PacketType type = (PacketType)reader.BeginChunk(0); + + if(reader.IsErrored()) + { + SAFE_DELETE(m_Socket); + return; + } + + if(type != ePacket_Handshake && type != ePacket_Busy) + { + RDCERR("Expected handshake packet, got %d", type); + SAFE_DELETE(m_Socket); + } // failed handshaking - if(m_Socket == NULL || ser == NULL) + if(m_Socket == NULL) return; - RDCASSERT(type == ePacket_Handshake || type == ePacket_Busy); + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(m_Target); + SERIALISE_ELEMENT(m_API); + SERIALISE_ELEMENT(m_PID); + } + + reader.EndChunk(); if(type == ePacket_Handshake) { - ser->Serialise("", m_Target); - ser->Serialise("", m_API); - ser->Serialise("", m_PID); - RDCLOG("Got remote handshake: %s (%s) [%u]", m_Target.c_str(), m_API.c_str(), m_PID); } else if(type == ePacket_Busy) { - ser->Serialise("", m_Target); - ser->Serialise("", m_API); - ser->Serialise("", m_BusyClient); - RDCLOG("Got remote busy signal: %s (%s) owned by %s", m_Target.c_str(), m_API.c_str(), m_BusyClient.c_str()); } - - SAFE_DELETE(ser); } virtual ~TargetControl() {} @@ -436,37 +475,34 @@ public: const char *GetBusyClient() { return m_BusyClient.c_str(); } void TriggerCapture(uint32_t numFrames) { - Serialiser ser("", Serialiser::WRITING, false); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_TriggerCapture); - ser.Serialise("", numFrames); + SERIALISE_ELEMENT(numFrames); - if(!SendPacket(m_Socket, ePacket_TriggerCapture, ser)) - { + if(ser.IsErrored()) SAFE_DELETE(m_Socket); - return; - } } void QueueCapture(uint32_t frameNumber) { - Serialiser ser("", Serialiser::WRITING, false); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_QueueCapture); - ser.Serialise("", frameNumber); + SERIALISE_ELEMENT(frameNumber); - if(!SendPacket(m_Socket, ePacket_QueueCapture, ser)) - { + if(ser.IsErrored()) SAFE_DELETE(m_Socket); - return; - } } void CopyCapture(uint32_t remoteID, const char *localpath) { - Serialiser ser("", Serialiser::WRITING, false); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_CopyCapture); - ser.Serialise("", remoteID); + SERIALISE_ELEMENT(remoteID); - if(!SendPacket(m_Socket, ePacket_CopyCapture, ser)) + if(ser.IsErrored()) { SAFE_DELETE(m_Socket); return; @@ -477,15 +513,13 @@ public: void DeleteCapture(uint32_t remoteID) { - Serialiser ser("", Serialiser::WRITING, false); + WRITE_DATA_SCOPE(); + SCOPED_SERIALISE_CHUNK(ePacket_DeleteCapture); - ser.Serialise("", remoteID); + SERIALISE_ELEMENT(remoteID); - if(!SendPacket(m_Socket, ePacket_DeleteCapture, ser)) - { + if(ser.IsErrored()) SAFE_DELETE(m_Socket); - return; - } } TargetControlMessage ReceiveMessage() @@ -513,164 +547,149 @@ public: return msg; } - PacketType type; - Serialiser *ser = NULL; + PacketType type = (PacketType)reader.BeginChunk(0); - GetPacket(type, ser); - - if(m_Socket == NULL) + if(reader.IsErrored()) { - SAFE_DELETE(ser); + SAFE_DELETE(m_Socket); msg.Type = TargetControlMessageType::Disconnected; return msg; } - else + else if(type == ePacket_Noop) { - if(type == ePacket_Noop) - { - SAFE_DELETE(ser); + msg.Type = TargetControlMessageType::Noop; + reader.EndChunk(); + return msg; + } + else if(type == ePacket_Busy) + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(msg.Busy.ClientName).Named("Client Name"); - msg.Type = TargetControlMessageType::Noop; - return msg; + SAFE_DELETE(m_Socket); + + RDCLOG("Got busy signal: '%s", msg.Busy.ClientName.c_str()); + msg.Type = TargetControlMessageType::Busy; + return msg; + } + else if(type == ePacket_NewChild) + { + msg.Type = TargetControlMessageType::NewChild; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(msg.NewChild.PID).Named("PID"); + SERIALISE_ELEMENT(msg.NewChild.ident).Named("Child ident"); + + RDCLOG("Got a new child process: %u %u", msg.NewChild.PID, msg.NewChild.ident); + + reader.EndChunk(); + return msg; + } + else if(type == ePacket_NewCapture) + { + msg.Type = TargetControlMessageType::NewCapture; + + bytebuf thumbnail; + + { + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(msg.NewCapture.ID).Named("Capture ID"); + SERIALISE_ELEMENT(msg.NewCapture.timestamp).Named("timestamp"); + SERIALISE_ELEMENT(msg.NewCapture.path).Named("path"); + SERIALISE_ELEMENT(thumbnail); } - else if(type == ePacket_Busy) + + msg.NewCapture.local = FileIO::exists(msg.NewCapture.path.c_str()); + + RDCLOG("Got a new capture: %d (time %llu) %d byte thumbnail", msg.NewCapture.ID, + msg.NewCapture.timestamp, thumbnail.count()); + + int w = 0; + int h = 0; + int comp = 3; + byte *thumbpixels = jpgd::decompress_jpeg_image_from_memory( + thumbnail.data(), thumbnail.count(), &w, &h, &comp, 3); + + if(w > 0 && h > 0 && thumbpixels) { - string existingClient; - ser->Serialise("", existingClient); + msg.NewCapture.thumbWidth = w; + msg.NewCapture.thumbHeight = h; + msg.NewCapture.thumbnail.assign(thumbpixels, w * h * 3); + } + else + { + msg.NewCapture.thumbWidth = 0; + msg.NewCapture.thumbHeight = 0; + } - SAFE_DELETE(ser); + free(thumbpixels); + reader.EndChunk(); + return msg; + } + else if(type == ePacket_RegisterAPI) + { + msg.Type = TargetControlMessageType::RegisterAPI; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(msg.RegisterAPI.APIName).Named("API Name"); + + RDCLOG("Used API: %s", msg.RegisterAPI.APIName.c_str()); + + reader.EndChunk(); + return msg; + } + else if(type == ePacket_CopyCapture) + { + msg.Type = TargetControlMessageType::CaptureCopied; + + READ_DATA_SCOPE(); + SERIALISE_ELEMENT(msg.NewCapture.ID).Named("Capture ID"); + + msg.NewCapture.path = m_CaptureCopies[msg.NewCapture.ID]; + + StreamWriter streamWriter(FileIO::fopen(msg.NewCapture.path.c_str(), "wb"), Ownership::Stream); + + ser.SerialiseStream(msg.NewCapture.path.c_str(), streamWriter, NULL); + + if(reader.IsErrored()) + { SAFE_DELETE(m_Socket); - RDCLOG("Got busy signal: '%s", existingClient.c_str()); - msg.Type = TargetControlMessageType::Busy; - msg.Busy.ClientName = existingClient; + msg.Type = TargetControlMessageType::Disconnected; return msg; } - else if(type == ePacket_CopyCapture) - { - msg.Type = TargetControlMessageType::CaptureCopied; - ser->Serialise("", msg.NewCapture.ID); + m_CaptureCopies.erase(msg.NewCapture.ID); - SAFE_DELETE(ser); - - msg.NewCapture.path = m_CaptureCopies[msg.NewCapture.ID]; - - if(!RecvChunkedFile(m_Socket, ePacket_CopyCapture, msg.NewCapture.path.c_str(), ser, NULL)) - { - SAFE_DELETE(ser); - SAFE_DELETE(m_Socket); - - msg.Type = TargetControlMessageType::Disconnected; - return msg; - } - - m_CaptureCopies.erase(msg.NewCapture.ID); - - SAFE_DELETE(ser); - - return msg; - } - else if(type == ePacket_NewChild) - { - msg.Type = TargetControlMessageType::NewChild; - - ser->Serialise("", msg.NewChild.PID); - ser->Serialise("", msg.NewChild.ident); - - RDCLOG("Got a new child process: %u %u", msg.NewChild.PID, msg.NewChild.ident); - - SAFE_DELETE(ser); - - return msg; - } - else if(type == ePacket_NewCapture) - { - msg.Type = TargetControlMessageType::NewCapture; - - ser->Serialise("", msg.NewCapture.ID); - ser->Serialise("", msg.NewCapture.timestamp); - - string path; - ser->Serialise("", path); - msg.NewCapture.path = path; - msg.NewCapture.local = FileIO::exists(path.c_str()); - - int32_t thumblen = 0; - ser->Serialise("", thumblen); - - byte *buf = new byte[thumblen]; - - size_t l = 0; - ser->SerialiseBuffer("", buf, l); - - RDCLOG("Got a new capture: %d (time %llu) %d byte thumbnail", msg.NewCapture.ID, - msg.NewCapture.timestamp, thumblen); - - int w = 0; - int h = 0; - int comp = 3; - byte *thumbpixels = jpgd::decompress_jpeg_image_from_memory(buf, thumblen, &w, &h, &comp, 3); - - if(w > 0 && h > 0 && thumbpixels) - { - msg.NewCapture.thumbWidth = w; - msg.NewCapture.thumbHeight = h; - msg.NewCapture.thumbnail.assign(thumbpixels, w * h * 3); - } - else - { - msg.NewCapture.thumbWidth = 0; - msg.NewCapture.thumbHeight = 0; - } - - free(thumbpixels); - - SAFE_DELETE(ser); - - return msg; - } - else if(type == ePacket_RegisterAPI) - { - msg.Type = TargetControlMessageType::RegisterAPI; - - ser->Serialise("", m_API); - msg.RegisterAPI.APIName = m_API; - - RDCLOG("Used API: %s", m_API.c_str()); - - SAFE_DELETE(ser); - - return msg; - } + reader.EndChunk(); + return msg; } + else + { + RDCERR("Unexpected packed received: %d", type); + SAFE_DELETE(m_Socket); - SAFE_DELETE(ser); - - msg.Type = TargetControlMessageType::Noop; - return msg; + msg.Type = TargetControlMessageType::Disconnected; + return msg; + } } private: Network::Socket *m_Socket; - string m_Target, m_API, m_BusyClient; + WriteSerialiser writer; + ReadSerialiser reader; + std::string m_Target, m_API, m_BusyClient; uint32_t m_PID; - map m_CaptureCopies; - - void GetPacket(PacketType &type, Serialiser *&ser) - { - if(!RecvPacket(m_Socket, type, &ser)) - SAFE_DELETE(m_Socket); - } + std::map m_CaptureCopies; }; extern "C" RENDERDOC_API ITargetControl *RENDERDOC_CC RENDERDOC_CreateTargetControl( const char *host, uint32_t ident, const char *clientName, bool forceConnection) { - string s = "localhost"; + std::string s = "localhost"; if(host != NULL && host[0] != '\0') s = host;