mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-28 09:26:52 +00:00
Add error checking and handling while loading captures
* Previously once we started loading a capture we'd blindly continue until we loaded it (and then it's assumed to be successful), or we crash. * Now errors can be reported during serialisation and bubbled up to abort the file load process. The next steps are to add error checking in each function serialise before doing any replay calls to the API with potentially corrupt data, and on top of that catching API-only errors when the serialisation is (seemingly) fine, and propagating those in a reasonable way. * We also harden the serialisation a bit so that if it reads an obviously invalid byte length for a buffer or array count, it won't continue. It's still not perfect as the sizes could still be large and invalid but within range, but it should catch the worst cases.
This commit is contained in:
@@ -423,7 +423,13 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile, float *pr
|
||||
}
|
||||
|
||||
if(m_Renderer == NULL)
|
||||
{
|
||||
if(m_CaptureFile)
|
||||
m_CaptureFile->Shutdown();
|
||||
m_CaptureFile = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
qInfo() << "QRenderDoc - renderer created for" << capturefile;
|
||||
|
||||
|
||||
@@ -423,10 +423,18 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
|
||||
{
|
||||
ICaptureFile *file = RENDERDOC_OpenCaptureFile();
|
||||
|
||||
if(file->OpenFile(filename.toUtf8().data(), "rdc") != ReplayStatus::Succeeded)
|
||||
ReplayStatus status = file->OpenFile(filename.toUtf8().data(), "rdc");
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
{
|
||||
RDDialog::critical(NULL, tr("Error opening capture"),
|
||||
tr("Couldn't open file '%1'").arg(filename));
|
||||
QString text = tr("Couldn't open file '%1'\n").arg(filename);
|
||||
QString message = file->ErrorString();
|
||||
if(message.isEmpty())
|
||||
text += tr("%1").arg(ToQStr(status));
|
||||
else
|
||||
text += tr("%1: %2").arg(ToQStr(status)).arg(message);
|
||||
|
||||
RDDialog::critical(NULL, tr("Error opening capture"), text);
|
||||
|
||||
file->Shutdown();
|
||||
return;
|
||||
@@ -559,6 +567,8 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
|
||||
}
|
||||
}
|
||||
|
||||
statusText->setText(tr("Loading %1...").arg(origFilename));
|
||||
|
||||
m_Ctx.LoadCapture(fileToLoad, origFilename, temporary, local);
|
||||
}
|
||||
|
||||
@@ -566,8 +576,6 @@ void MainWindow::LoadCapture(const QString &filename, bool temporary, bool local
|
||||
{
|
||||
m_Ctx.Config().LastCaptureFilePath = QFileInfo(filename).absolutePath();
|
||||
}
|
||||
|
||||
statusText->setText(tr("Loading %1...").arg(origFilename));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,6 +984,7 @@ void MainWindow::setProgress(float val)
|
||||
if(val < 0.0f || val >= 1.0f)
|
||||
{
|
||||
statusProgress->setVisible(false);
|
||||
statusText->setText(QString());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1406,6 +1406,16 @@ representation back to native RDC.
|
||||
)");
|
||||
virtual ReplayStatus Convert(const char *filename, const char *filetype, float *progress) = 0;
|
||||
|
||||
DOCUMENT(R"(Returns the human-readable error string for the last error received.
|
||||
|
||||
The error string is not reset by calling this function so it's safe to call multiple times. However
|
||||
any other function call may reset the error string to empty.
|
||||
|
||||
:return: The error string, if one exists, or an empty string.
|
||||
:rtype: str
|
||||
)");
|
||||
virtual rdcstr ErrorString() = 0;
|
||||
|
||||
DOCUMENT(R"(Returns the list of capture file formats.
|
||||
|
||||
:return: The list of capture file formats available.
|
||||
|
||||
@@ -39,10 +39,16 @@ std::string DoStringise(const ReplayStatus &el)
|
||||
STRINGISE_ENUM_CLASS_NAMED(FileIOFailed, "File I/O failed");
|
||||
STRINGISE_ENUM_CLASS_NAMED(FileIncompatibleVersion, "File of incompatible version");
|
||||
STRINGISE_ENUM_CLASS_NAMED(FileCorrupted, "File corrupted");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIUnsupported, "API unsupported");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIUnsupported, "API is not unsupported");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIInitFailed, "API initialisation failed");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIIncompatibleVersion, "API incompatible version");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIHardwareUnsupported, "API hardware unsupported");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIIncompatibleVersion,
|
||||
"Captured API data has an incompatible version");
|
||||
STRINGISE_ENUM_CLASS_NAMED(
|
||||
APIHardwareUnsupported,
|
||||
"Current hardware unsupported or incompatible with captured hardware");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIDataCorrupted,
|
||||
"Replaying the capture encountered invalid/corrupted data");
|
||||
STRINGISE_ENUM_CLASS_NAMED(APIReplayFailed, "Replaying the capture failed at the API level");
|
||||
}
|
||||
END_ENUM_STRINGISE();
|
||||
}
|
||||
|
||||
@@ -2833,6 +2833,15 @@ a remote server.
|
||||
.. data:: APIHardwareUnsupported
|
||||
|
||||
The API is not supported on the currently available hardware.
|
||||
|
||||
.. data:: APIDataCorrupted
|
||||
|
||||
While loading the capture for replay, the driver encountered corrupted or invalid serialised data.
|
||||
|
||||
.. data:: APIReplayFailed
|
||||
|
||||
The API failed to replay the capture, with some runtime error that couldn't be determined until
|
||||
the replay began.
|
||||
)");
|
||||
enum class ReplayStatus : uint32_t
|
||||
{
|
||||
@@ -2853,6 +2862,8 @@ enum class ReplayStatus : uint32_t
|
||||
APIInitFailed,
|
||||
APIIncompatibleVersion,
|
||||
APIHardwareUnsupported,
|
||||
APIDataCorrupted,
|
||||
APIReplayFailed,
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_ENUM(ReplayStatus);
|
||||
|
||||
@@ -151,7 +151,10 @@ 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, bool storeStructuredBuffers) {}
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
const SDFile &GetStructuredFile() { return m_File; }
|
||||
void RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws, const MeshDisplay &cfg)
|
||||
{
|
||||
|
||||
@@ -205,6 +205,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
|
||||
ReadSerialiser reader(new StreamReader(client, Ownership::Nothing), Ownership::Stream);
|
||||
|
||||
writer.SetStreamingMode(true);
|
||||
reader.SetStreamingMode(true);
|
||||
|
||||
while(client)
|
||||
{
|
||||
@@ -429,15 +430,25 @@ static void ActiveRemoteClientThread(ClientThread *threadData)
|
||||
}
|
||||
else
|
||||
{
|
||||
driver->ReadLogInitialisation(rdc, false);
|
||||
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);
|
||||
|
||||
proxy = new ReplayProxy(reader, writer, driver);
|
||||
kill = true;
|
||||
Threading::JoinThread(ticker);
|
||||
Threading::CloseThread(ticker);
|
||||
|
||||
proxy = new ReplayProxy(reader, writer, driver);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -966,6 +977,7 @@ public:
|
||||
writer(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream)
|
||||
{
|
||||
writer.SetStreamingMode(true);
|
||||
reader.SetStreamingMode(true);
|
||||
|
||||
std::map<RDCDriver, std::string> m = RenderDoc::Inst().GetReplayDrivers();
|
||||
|
||||
|
||||
@@ -120,7 +120,10 @@ public:
|
||||
|
||||
bool IsRemoteProxy() { return !m_RemoteServer; }
|
||||
void Shutdown() { delete this; }
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) {}
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
vector<WindowingSystem> GetSupportedWindowSystems()
|
||||
{
|
||||
if(m_Proxy)
|
||||
|
||||
@@ -76,6 +76,7 @@ void RenderDoc::TargetControlClientThread(Network::Socket *client)
|
||||
ReadSerialiser reader(new StreamReader(client, Ownership::Nothing), Ownership::Stream);
|
||||
|
||||
writer.SetStreamingMode(true);
|
||||
reader.SetStreamingMode(true);
|
||||
|
||||
std::string api = "";
|
||||
RDCDriver driver;
|
||||
@@ -404,6 +405,7 @@ public:
|
||||
std::vector<byte> payload;
|
||||
|
||||
writer.SetStreamingMode(true);
|
||||
reader.SetStreamingMode(true);
|
||||
|
||||
m_PID = 0;
|
||||
|
||||
|
||||
@@ -912,17 +912,17 @@ void WrappedID3D11Device::Serialise_CaptureScope(SerialiserType &ser)
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture);
|
||||
|
||||
if(sectionIdx < 0)
|
||||
return;
|
||||
return ReplayStatus::FileCorrupted;
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
if(reader->IsErrored())
|
||||
return;
|
||||
return ReplayStatus::FileIOFailed;
|
||||
|
||||
ReadSerialiser ser(reader, Ownership::Stream);
|
||||
|
||||
@@ -961,10 +961,16 @@ void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructur
|
||||
|
||||
chunkIdx++;
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
ProcessChunk(ser, context);
|
||||
|
||||
ser.EndChunk();
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
uint64_t offsetEnd = reader->GetOffset();
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offsetEnd) / float(reader->GetSize()));
|
||||
@@ -1027,6 +1033,8 @@ void WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructur
|
||||
|
||||
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
|
||||
m_FrameRecord.frameInfo.persistentSize);
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
void WrappedID3D11Device::ReplayLog(uint32_t startEventID, uint32_t endEventID,
|
||||
|
||||
@@ -514,7 +514,7 @@ public:
|
||||
m_SectionVersion = sectionVersion;
|
||||
m_State = CaptureState::StructuredExport;
|
||||
}
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ProcessChunk(ReadSerialiser &ser, D3D11Chunk context);
|
||||
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
|
||||
|
||||
|
||||
@@ -1218,9 +1218,9 @@ void D3D11Replay::SavePipelineState()
|
||||
}
|
||||
}
|
||||
|
||||
void D3D11Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus D3D11Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
return m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
}
|
||||
|
||||
void D3D11Replay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
|
||||
@@ -1896,7 +1896,7 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!D3D11InitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible D3D11 serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
@@ -2051,9 +2051,10 @@ void D3D11_ProcessStructured(RDCFile *rdc, SDFile &output)
|
||||
return;
|
||||
|
||||
device.SetStructuredExport(rdc->GetSectionProperties(sectionIdx).version);
|
||||
device.ReadLogInitialisation(rdc, true);
|
||||
ReplayStatus status = device.ReadLogInitialisation(rdc, true);
|
||||
|
||||
device.GetStructuredFile().swap(output);
|
||||
if(status == ReplayStatus::Succeeded)
|
||||
device.GetStructuredFile().swap(output);
|
||||
}
|
||||
|
||||
static StructuredProcessRegistration D3D11ProcessRegistration(RDC_D3D11, &D3D11_ProcessStructured);
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
void FreeTargetResource(ResourceId id);
|
||||
void FreeCustomShader(ResourceId id);
|
||||
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
const SDFile &GetStructuredFile();
|
||||
|
||||
|
||||
@@ -2367,17 +2367,17 @@ void WrappedID3D12Device::AddResourceCurChunk(ResourceId id)
|
||||
AddResourceCurChunk(GetReplay()->GetResourceDesc(id));
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture);
|
||||
|
||||
if(sectionIdx < 0)
|
||||
return;
|
||||
return ReplayStatus::FileCorrupted;
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
if(reader->IsErrored())
|
||||
return;
|
||||
return ReplayStatus::FileIOFailed;
|
||||
|
||||
ReadSerialiser ser(reader, Ownership::Stream);
|
||||
|
||||
@@ -2416,10 +2416,16 @@ void WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructur
|
||||
|
||||
chunkIdx++;
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
ProcessChunk(ser, context);
|
||||
|
||||
ser.EndChunk();
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
uint64_t offsetEnd = reader->GetOffset();
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offsetEnd) / float(reader->GetSize()));
|
||||
@@ -2498,6 +2504,8 @@ void WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool storeStructur
|
||||
|
||||
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
|
||||
m_FrameRecord.frameInfo.persistentSize);
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID,
|
||||
|
||||
@@ -474,7 +474,7 @@ public:
|
||||
bool Serialise_DynamicDescriptorCopies(SerialiserType &ser,
|
||||
const std::vector<DynamicDescriptorCopy> &DescriptorCopies);
|
||||
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
|
||||
|
||||
void SetStructuredExport(uint64_t sectionVersion)
|
||||
|
||||
@@ -59,9 +59,9 @@ void D3D12Replay::Shutdown()
|
||||
D3D12Replay::PostDeviceShutdownCounters();
|
||||
}
|
||||
|
||||
void D3D12Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus D3D12Replay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
return m_pDevice->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
}
|
||||
|
||||
APIProperties D3D12Replay::GetAPIProperties()
|
||||
@@ -1752,7 +1752,7 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!D3D12InitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible D3D11 serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
@@ -1816,9 +1816,10 @@ void D3D12_ProcessStructured(RDCFile *rdc, SDFile &output)
|
||||
return;
|
||||
|
||||
device.SetStructuredExport(rdc->GetSectionProperties(sectionIdx).version);
|
||||
device.ReadLogInitialisation(rdc, true);
|
||||
ReplayStatus status = device.ReadLogInitialisation(rdc, true);
|
||||
|
||||
device.GetStructuredFile().swap(output);
|
||||
if(status == ReplayStatus::Succeeded)
|
||||
device.GetStructuredFile().swap(output);
|
||||
}
|
||||
|
||||
static StructuredProcessRegistration D3D12ProcessRegistration(RDC_D3D12, &D3D12_ProcessStructured);
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
void FreeTargetResource(ResourceId id);
|
||||
void FreeCustomShader(ResourceId id);
|
||||
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool readStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool readStructuredBuffers);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
const SDFile &GetStructuredFile();
|
||||
|
||||
|
||||
@@ -3054,17 +3054,17 @@ void WrappedOpenGL::AddResourceInitChunk(GLResource res)
|
||||
}
|
||||
}
|
||||
|
||||
void WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture);
|
||||
|
||||
if(sectionIdx < 0)
|
||||
return;
|
||||
return ReplayStatus::FileCorrupted;
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
if(reader->IsErrored())
|
||||
return;
|
||||
return ReplayStatus::FileIOFailed;
|
||||
|
||||
ReadSerialiser ser(reader, Ownership::Stream);
|
||||
|
||||
@@ -3103,10 +3103,16 @@ void WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuff
|
||||
|
||||
chunkIdx++;
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
ProcessChunk(ser, context);
|
||||
|
||||
ser.EndChunk();
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
uint64_t offsetEnd = reader->GetOffset();
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offsetEnd) / float(reader->GetSize()));
|
||||
@@ -3161,6 +3167,8 @@ void WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuff
|
||||
|
||||
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
|
||||
m_FrameRecord.frameInfo.persistentSize);
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
void WrappedOpenGL::ProcessChunk(ReadSerialiser &ser, GLChunk chunk)
|
||||
|
||||
@@ -559,7 +559,7 @@ public:
|
||||
// replay interface
|
||||
void Initialise(GLInitParams ¶ms, uint64_t sectionVersion);
|
||||
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
|
||||
GLuint GetFakeBBFBO() { return m_FakeBB_FBO; }
|
||||
GLuint GetFakeVAO() { return m_FakeVAO; }
|
||||
|
||||
@@ -73,10 +73,10 @@ void GLReplay::Shutdown()
|
||||
GLReplay::PostContextShutdownCounters();
|
||||
}
|
||||
|
||||
void GLReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus GLReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
MakeCurrentReplayContext(&m_ReplayCtx);
|
||||
m_pDriver->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
return m_pDriver->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
}
|
||||
|
||||
void GLReplay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
|
||||
@@ -3341,9 +3341,10 @@ void GL_ProcessStructured(RDCFile *rdc, SDFile &output)
|
||||
return;
|
||||
|
||||
device.SetStructuredExport(rdc->GetSectionProperties(sectionIdx).version);
|
||||
device.ReadLogInitialisation(rdc, true);
|
||||
ReplayStatus status = device.ReadLogInitialisation(rdc, true);
|
||||
|
||||
device.GetStructuredFile().swap(output);
|
||||
if(status == ReplayStatus::Succeeded)
|
||||
device.GetStructuredFile().swap(output);
|
||||
}
|
||||
|
||||
static StructuredProcessRegistration GLProcessRegistration(RDC_OpenGL, &GL_ProcessStructured);
|
||||
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
const VKPipe::State &GetVulkanPipelineState() { return m_VKState; }
|
||||
void FreeTargetResource(ResourceId id);
|
||||
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
const SDFile &GetStructuredFile();
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ ReplayStatus GLES_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!GLInitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible D3D11 serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
@@ -108,7 +108,7 @@ ReplayStatus GL_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!GLInitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible D3D11 serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
@@ -70,7 +70,7 @@ ReplayStatus GL_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!GLInitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible D3D11 serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
@@ -1420,17 +1420,17 @@ void WrappedVulkan::AddResourceCurChunk(ResourceId id)
|
||||
AddResourceCurChunk(GetReplay()->GetResourceDesc(id));
|
||||
}
|
||||
|
||||
void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
int sectionIdx = rdc->SectionIndex(SectionType::FrameCapture);
|
||||
|
||||
if(sectionIdx < 0)
|
||||
return;
|
||||
return ReplayStatus::FileCorrupted;
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
|
||||
if(reader->IsErrored())
|
||||
return;
|
||||
return ReplayStatus::FileIOFailed;
|
||||
|
||||
ReadSerialiser ser(reader, Ownership::Stream);
|
||||
|
||||
@@ -1469,10 +1469,16 @@ void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuff
|
||||
|
||||
chunkIdx++;
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
ProcessChunk(ser, context);
|
||||
|
||||
ser.EndChunk();
|
||||
|
||||
if(reader->IsErrored())
|
||||
return ReplayStatus::APIDataCorrupted;
|
||||
|
||||
uint64_t offsetEnd = reader->GetOffset();
|
||||
|
||||
RenderDoc::Inst().SetProgress(FileInitialRead, float(offsetEnd) / float(reader->GetSize()));
|
||||
@@ -1533,6 +1539,8 @@ void WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuff
|
||||
RDCASSERT(m_Device != VK_NULL_HANDLE && m_Queue != VK_NULL_HANDLE &&
|
||||
m_InternalCmds.cmdpool != VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
void WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t startEventID,
|
||||
|
||||
@@ -763,7 +763,7 @@ public:
|
||||
}
|
||||
void Shutdown();
|
||||
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
|
||||
SDFile &GetStructuredFile() { return *m_StructuredFile; }
|
||||
FrameRecord &GetFrameRecord() { return m_FrameRecord; }
|
||||
|
||||
@@ -659,9 +659,9 @@ APIProperties VulkanReplay::GetAPIProperties()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VulkanReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
ReplayStatus VulkanReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
m_pDriver->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
return m_pDriver->ReadLogInitialisation(rdc, storeStructuredBuffers);
|
||||
}
|
||||
|
||||
void VulkanReplay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
|
||||
@@ -5360,7 +5360,7 @@ ReplayStatus Vulkan_CreateReplayDevice(RDCFile *rdc, IReplayDriver **driver)
|
||||
if(!VkInitParams::IsSupportedVersion(ver))
|
||||
{
|
||||
RDCERR("Incompatible Vulkan serialise version %llu", ver);
|
||||
return ReplayStatus::APIUnsupported;
|
||||
return ReplayStatus::APIIncompatibleVersion;
|
||||
}
|
||||
|
||||
StreamReader *reader = rdc->ReadSection(sectionIdx);
|
||||
@@ -5428,9 +5428,10 @@ void Vulkan_ProcessStructured(RDCFile *rdc, SDFile &output)
|
||||
return;
|
||||
|
||||
vulkan.SetStructuredExport(rdc->GetSectionProperties(sectionIdx).version);
|
||||
vulkan.ReadLogInitialisation(rdc, true);
|
||||
ReplayStatus status = vulkan.ReadLogInitialisation(rdc, true);
|
||||
|
||||
vulkan.GetStructuredFile().swap(output);
|
||||
if(status == ReplayStatus::Succeeded)
|
||||
vulkan.GetStructuredFile().swap(output);
|
||||
}
|
||||
|
||||
static StructuredProcessRegistration VulkanProcessRegistration(RDC_Vulkan, &Vulkan_ProcessStructured);
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
const VKPipe::State &GetVulkanPipelineState() { return m_VulkanPipelineState; }
|
||||
void FreeTargetResource(ResourceId id);
|
||||
|
||||
void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
const SDFile &GetStructuredFile();
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public:
|
||||
ReplayStatus OpenFile(const char *filename, const char *filetype);
|
||||
ReplayStatus OpenBuffer(const bytebuf &buffer, const char *filetype);
|
||||
bool CopyFileTo(const char *filename);
|
||||
|
||||
rdcstr ErrorString() { return m_ErrorString; }
|
||||
void Shutdown() { delete this; }
|
||||
ReplaySupport LocalReplaySupport() { return m_Support; }
|
||||
const char *DriverName() { return m_DriverName.c_str(); }
|
||||
@@ -183,7 +183,7 @@ private:
|
||||
|
||||
SDFile m_StructuredData;
|
||||
|
||||
std::string m_DriverName, m_Ident;
|
||||
std::string m_DriverName, m_Ident, m_ErrorString;
|
||||
ReplaySupport m_Support = ReplaySupport::Unsupported;
|
||||
};
|
||||
|
||||
@@ -214,6 +214,7 @@ ReplayStatus CaptureFile::OpenFile(const char *filename, const char *filetype)
|
||||
|
||||
if(ret != ReplayStatus::Succeeded)
|
||||
{
|
||||
m_ErrorString = StringFormat::Fmt("Importer '%s' failed to import file.", filetype);
|
||||
delete m_RDC;
|
||||
return ret;
|
||||
}
|
||||
@@ -249,6 +250,7 @@ ReplayStatus CaptureFile::OpenBuffer(const bytebuf &buffer, const char *filetype
|
||||
|
||||
if(ret != ReplayStatus::Succeeded)
|
||||
{
|
||||
m_ErrorString = StringFormat::Fmt("Importer '%s' failed to import file.", filetype);
|
||||
delete m_RDC;
|
||||
return ret;
|
||||
}
|
||||
@@ -278,6 +280,8 @@ ReplayStatus CaptureFile::Init()
|
||||
if(!m_RDC)
|
||||
return ReplayStatus::InternalError;
|
||||
|
||||
m_ErrorString = m_RDC->ErrorString();
|
||||
|
||||
switch(m_RDC->ErrorCode())
|
||||
{
|
||||
case ContainerError::FileNotFound: return ReplayStatus::FileNotFound; break;
|
||||
|
||||
@@ -1586,7 +1586,10 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
|
||||
{
|
||||
m_pDevice = device;
|
||||
|
||||
m_pDevice->ReadLogInitialisation(rdc, false);
|
||||
ReplayStatus status = m_pDevice->ReadLogInitialisation(rdc, false);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
return status;
|
||||
|
||||
FetchPipelineState();
|
||||
|
||||
@@ -1612,6 +1615,9 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
|
||||
|
||||
m_FrameRecord = m_pDevice->GetFrameRecord();
|
||||
|
||||
if(m_FrameRecord.drawcallList.empty())
|
||||
return ReplayStatus::APIReplayFailed;
|
||||
|
||||
DrawcallDescription *previous = NULL;
|
||||
SetupDrawcallPointers(&m_Drawcalls, m_FrameRecord.drawcallList, NULL, previous);
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
|
||||
virtual FrameRecord GetFrameRecord() = 0;
|
||||
|
||||
virtual void ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) = 0;
|
||||
virtual ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers) = 0;
|
||||
virtual void ReplayLog(uint32_t endEventID, ReplayLogType replayType) = 0;
|
||||
virtual const SDFile &GetStructuredFile() = 0;
|
||||
|
||||
|
||||
@@ -223,11 +223,17 @@ struct BinarySectionHeader
|
||||
};
|
||||
};
|
||||
|
||||
#define RETURNCORRUPT(...) \
|
||||
{ \
|
||||
RDCERR(__VA_ARGS__); \
|
||||
m_Error = ContainerError::Corrupt; \
|
||||
return; \
|
||||
#define SETERROR(error, ...) \
|
||||
{ \
|
||||
m_ErrorString = StringFormat::Fmt(__VA_ARGS__); \
|
||||
RDCERR("%s", m_ErrorString.c_str()); \
|
||||
m_Error = error; \
|
||||
}
|
||||
|
||||
#define RETURNERROR(error, ...) \
|
||||
{ \
|
||||
SETERROR(error, __VA_ARGS__); \
|
||||
return; \
|
||||
}
|
||||
|
||||
RDCFile::~RDCFile()
|
||||
@@ -245,8 +251,7 @@ void RDCFile::Open(const char *path)
|
||||
// empty path.
|
||||
if(path == NULL || path[0] == 0)
|
||||
{
|
||||
m_Error = ContainerError::FileNotFound;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileNotFound, "Invalid file path specified");
|
||||
}
|
||||
|
||||
RDCLOG("Opening RDCFile %s", path);
|
||||
@@ -260,9 +265,8 @@ void RDCFile::Open(const char *path)
|
||||
|
||||
if(!m_File)
|
||||
{
|
||||
RDCERR("Can't open capture file '%s' for read - errno %d", path, errno);
|
||||
m_Error = ContainerError::FileNotFound;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileNotFound, "Can't open capture file '%s' for read - errno %d",
|
||||
path, errno);
|
||||
}
|
||||
|
||||
// try to identify if this is an image
|
||||
@@ -318,31 +322,30 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
RDCERR("I/O error reading magic number");
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error reading magic number");
|
||||
}
|
||||
|
||||
if(header.magic != MAGIC_HEADER)
|
||||
{
|
||||
RDCWARN("Invalid capture file. Expected magic %08x, got %08x.", MAGIC_HEADER,
|
||||
(uint32_t)header.magic);
|
||||
|
||||
m_Error = ContainerError::Corrupt;
|
||||
return;
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid capture file. Expected magic %08x, got %08x.",
|
||||
MAGIC_HEADER, (uint32_t)header.magic);
|
||||
}
|
||||
|
||||
m_SerVer = header.version;
|
||||
|
||||
if(m_SerVer != SERIALISE_VERSION)
|
||||
{
|
||||
RDCERR(
|
||||
"Capture file from wrong version. This program (v%s) is logfile version %llu, file is "
|
||||
"logfile version %llu capture on %s.",
|
||||
MAJOR_MINOR_VERSION_STRING, SERIALISE_VERSION, header.version, header.progVersion);
|
||||
if(header.version < V1_0_VERSION)
|
||||
{
|
||||
RDCEraseEl(header.progVersion);
|
||||
memcpy(header.progVersion, "v0.x", sizeof("v0.x"));
|
||||
}
|
||||
|
||||
m_Error = ContainerError::UnsupportedVersion;
|
||||
return;
|
||||
RETURNERROR(
|
||||
ContainerError::UnsupportedVersion,
|
||||
"Capture file from wrong version. This program (v%s) uses logfile version %u, this file is "
|
||||
"logfile version %u captured on %s.",
|
||||
MAJOR_MINOR_VERSION_STRING, SERIALISE_VERSION, header.version, header.progVersion);
|
||||
}
|
||||
|
||||
BinaryThumbnail thumb;
|
||||
@@ -350,15 +353,13 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
RDCERR("I/O error reading thumbnail header");
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error reading thumbnail header");
|
||||
}
|
||||
|
||||
// check the thumbnail size is sensible
|
||||
if(thumb.length > 10 * 1024 * 1024)
|
||||
{
|
||||
RETURNCORRUPT("Thumbnail byte length invalid: %u", thumb.length);
|
||||
RETURNERROR(ContainerError::Corrupt, "Thumbnail byte length invalid: %u", thumb.length);
|
||||
}
|
||||
|
||||
byte *thumbData = new byte[thumb.length];
|
||||
@@ -366,10 +367,8 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
RDCERR("I/O error reading thumbnail data");
|
||||
delete[] thumbData;
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error reading thumbnail data");
|
||||
}
|
||||
|
||||
CaptureMetaData meta;
|
||||
@@ -377,16 +376,15 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
RDCERR("I/O error reading capture metadata");
|
||||
delete[] thumbData;
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error reading capture metadata");
|
||||
}
|
||||
|
||||
if(meta.driverNameLength == 0)
|
||||
{
|
||||
delete[] thumbData;
|
||||
RETURNCORRUPT("Driver name length is invalid, must be at least 1 to contain NULL terminator");
|
||||
RETURNERROR(ContainerError::Corrupt,
|
||||
"Driver name length is invalid, must be at least 1 to contain NULL terminator");
|
||||
}
|
||||
|
||||
char *driverName = new char[meta.driverNameLength];
|
||||
@@ -394,11 +392,9 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.IsErrored())
|
||||
{
|
||||
RDCERR("I/O error reading driver name");
|
||||
delete[] thumbData;
|
||||
delete[] driverName;
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error reading driver name");
|
||||
}
|
||||
|
||||
driverName[meta.driverNameLength - 1] = '\0';
|
||||
@@ -421,9 +417,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(reader.GetOffset() > header.headerLength)
|
||||
{
|
||||
RDCERR("I/O error seeking to end of header");
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "I/O error seeking to end of header");
|
||||
}
|
||||
|
||||
reader.SkipBytes(header.headerLength - (uint32_t)reader.GetOffset());
|
||||
@@ -447,10 +441,10 @@ void RDCFile::Init(StreamReader &reader)
|
||||
char c = 0;
|
||||
reader.Read(c);
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Invalid ASCII data section '%hhx'", c);
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid ASCII data section '%hhx'", c);
|
||||
|
||||
if(reader.AtEnd())
|
||||
RETURNCORRUPT("Invalid truncated ASCII data section");
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid truncated ASCII data section");
|
||||
|
||||
uint64_t length = 0;
|
||||
|
||||
@@ -468,7 +462,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
}
|
||||
|
||||
if(reader.IsErrored() || reader.AtEnd())
|
||||
RETURNCORRUPT("Invalid truncated ASCII data section");
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid truncated ASCII data section");
|
||||
|
||||
uint32_t type = 0;
|
||||
|
||||
@@ -486,7 +480,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
}
|
||||
|
||||
if(reader.IsErrored() || reader.AtEnd())
|
||||
RETURNCORRUPT("Invalid truncated ASCII data section");
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid truncated ASCII data section");
|
||||
|
||||
uint64_t version = 0;
|
||||
|
||||
@@ -504,7 +498,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
}
|
||||
|
||||
if(reader.IsErrored() || reader.AtEnd())
|
||||
RETURNCORRUPT("Invalid truncated ASCII data section");
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid truncated ASCII data section");
|
||||
|
||||
std::string name;
|
||||
|
||||
@@ -521,7 +515,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
}
|
||||
|
||||
if(reader.IsErrored() || reader.AtEnd())
|
||||
RETURNCORRUPT("Invalid truncated ASCII data section");
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid truncated ASCII data section");
|
||||
|
||||
SectionProperties props;
|
||||
props.flags = SectionFlags::ASCIIStored;
|
||||
@@ -539,7 +533,8 @@ void RDCFile::Init(StreamReader &reader)
|
||||
reader.SkipBytes(loc.diskLength);
|
||||
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Error seeking past ASCII section '%s' data", name.c_str());
|
||||
RETURNERROR(ContainerError::Corrupt, "Error seeking past ASCII section '%s' data",
|
||||
name.c_str());
|
||||
|
||||
m_Sections.push_back(props);
|
||||
m_SectionLocations.push_back(loc);
|
||||
@@ -550,7 +545,7 @@ void RDCFile::Init(StreamReader &reader)
|
||||
reader.Read(reading, offsetof(BinarySectionHeader, name) - 1);
|
||||
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Error reading binary section header");
|
||||
RETURNERROR(ContainerError::Corrupt, "Error reading binary section header");
|
||||
|
||||
SectionProperties props;
|
||||
props.flags = sectionHeader.sectionFlags;
|
||||
@@ -561,7 +556,8 @@ void RDCFile::Init(StreamReader &reader)
|
||||
|
||||
if(sectionHeader.sectionNameLength == 0 || sectionHeader.sectionNameLength > 2 * 1024)
|
||||
{
|
||||
RETURNCORRUPT("Invalid section name length %u", sectionHeader.sectionNameLength);
|
||||
RETURNERROR(ContainerError::Corrupt, "Invalid section name length %u",
|
||||
sectionHeader.sectionNameLength);
|
||||
}
|
||||
|
||||
props.name.resize(sectionHeader.sectionNameLength - 1);
|
||||
@@ -569,12 +565,12 @@ void RDCFile::Init(StreamReader &reader)
|
||||
reader.Read(&props.name[0], sectionHeader.sectionNameLength - 1);
|
||||
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Error reading binary section header");
|
||||
RETURNERROR(ContainerError::Corrupt, "Error reading binary section header");
|
||||
|
||||
reader.SkipBytes(1);
|
||||
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Error reading binary section header");
|
||||
RETURNERROR(ContainerError::Corrupt, "Error reading binary section header");
|
||||
|
||||
SectionLocation loc;
|
||||
loc.headerOffset = headerOffset;
|
||||
@@ -587,17 +583,18 @@ void RDCFile::Init(StreamReader &reader)
|
||||
reader.SkipBytes(loc.diskLength);
|
||||
|
||||
if(reader.IsErrored())
|
||||
RETURNCORRUPT("Error seeking past binary section '%s' data", props.name.c_str());
|
||||
RETURNERROR(ContainerError::Corrupt, "Error seeking past binary section '%s' data",
|
||||
props.name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
RETURNCORRUPT("Unrecognised section type '%hhx'", sectionHeader.isASCII);
|
||||
RETURNERROR(ContainerError::Corrupt, "Unrecognised section type '%hhx'", sectionHeader.isASCII);
|
||||
}
|
||||
}
|
||||
|
||||
if(SectionIndex(SectionType::FrameCapture) == -1)
|
||||
{
|
||||
RETURNCORRUPT("Capture file doesn't have a frame capture");
|
||||
RETURNERROR(ContainerError::Corrupt, "Capture file doesn't have a frame capture");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,9 +646,8 @@ void RDCFile::Create(const char *filename)
|
||||
|
||||
if(!m_File)
|
||||
{
|
||||
RDCERR("Can't open capture file '%s' for write, errno %d", filename, errno);
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "Can't open capture file '%s' for write, errno %d",
|
||||
filename, errno);
|
||||
}
|
||||
|
||||
RDCDEBUG("Opened capture file for write");
|
||||
@@ -686,9 +682,7 @@ void RDCFile::Create(const char *filename)
|
||||
|
||||
if(writer.IsErrored())
|
||||
{
|
||||
RDCERR("Error writing file header");
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "Error writing file header");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1033,8 +1027,7 @@ StreamWriter *RDCFile::WriteSection(const SectionProperties &props)
|
||||
|
||||
if(numWritten != offsetof(BinarySectionHeader, name) + name.size() + 1)
|
||||
{
|
||||
RDCERR("Error seeking to end of file, errno %d", errno);
|
||||
m_Error = ContainerError::FileIO;
|
||||
SETERROR(ContainerError::FileIO, "Error seeking to end of file, errno %d", errno);
|
||||
return new StreamWriter(StreamWriter::InvalidStream);
|
||||
}
|
||||
|
||||
@@ -1097,9 +1090,7 @@ StreamWriter *RDCFile::WriteSection(const SectionProperties &props)
|
||||
|
||||
if(bytesWritten != 2 * sizeof(uint64_t))
|
||||
{
|
||||
RDCERR("Error applying fixup to section header, errno %d", errno);
|
||||
m_Error = ContainerError::FileIO;
|
||||
return;
|
||||
RETURNERROR(ContainerError::FileIO, "Error applying fixup to section header, errno %d", errno);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -54,6 +54,10 @@ public:
|
||||
// API that interprets the stream that can be bumped.
|
||||
static const uint32_t SERIALISE_VERSION = 0x00000100;
|
||||
|
||||
// this must never be changed - files before this were in the v0.x series and didn't have embedded
|
||||
// version numbers
|
||||
static const uint32_t V1_0_VERSION = 0x00000100;
|
||||
|
||||
~RDCFile();
|
||||
|
||||
// opens an existing file for read and/or modification. Error if file doesn't exist
|
||||
@@ -70,6 +74,7 @@ public:
|
||||
void Create(const char *filename);
|
||||
|
||||
ContainerError ErrorCode() const { return m_Error; }
|
||||
std::string ErrorString() const { return m_ErrorString; }
|
||||
RDCDriver GetDriver() const { return m_Driver; }
|
||||
const std::string &GetDriverName() const { return m_DriverName; }
|
||||
uint64_t GetMachineIdent() const { return m_MachineIdent; }
|
||||
@@ -102,6 +107,7 @@ private:
|
||||
RDCThumb m_Thumb;
|
||||
|
||||
ContainerError m_Error = ContainerError::NoError;
|
||||
std::string m_ErrorString;
|
||||
|
||||
struct SectionLocation
|
||||
{
|
||||
|
||||
@@ -198,7 +198,7 @@ void Serialiser<SerialiserMode::Reading>::EndChunk()
|
||||
// only skip remaining bytes if we have a valid length - if we have a length of 0 we wrote this
|
||||
// chunk in 'streaming mode' (see SetStreamingMode and the Writing EndChunk() impl) so there's
|
||||
// nothing to skip.
|
||||
if(m_ChunkMetadata.length > 0)
|
||||
if(m_ChunkMetadata.length > 0 && !m_Read->IsErrored())
|
||||
{
|
||||
// this will be a no-op if the last chunk length was accurate. If it was a
|
||||
// conservative estimate of the length then we'll skip some padding bytes
|
||||
|
||||
@@ -146,6 +146,14 @@ public:
|
||||
uint32_t BeginChunk(uint32_t chunkID, uint32_t byteLength);
|
||||
void EndChunk();
|
||||
|
||||
std::string GetCurChunkName()
|
||||
{
|
||||
if(m_ChunkLookup)
|
||||
return m_ChunkLookup(m_ChunkMetadata.chunkID);
|
||||
|
||||
return StringFormat::Fmt("<No Chunk Lookup: %u>", m_ChunkMetadata.chunkID);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@@ -213,7 +221,10 @@ public:
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(count);
|
||||
byteSize = count;
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
@@ -343,6 +354,11 @@ public:
|
||||
m_InternalElement = false;
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(count);
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
if(m_StructureStack.empty())
|
||||
@@ -411,6 +427,11 @@ public:
|
||||
m_InternalElement = false;
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(count);
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
if(m_StructureStack.empty())
|
||||
@@ -651,7 +672,10 @@ public:
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(count);
|
||||
arrayCount = count;
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
@@ -750,6 +774,11 @@ public:
|
||||
m_InternalElement = false;
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(size);
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
if(m_StructureStack.empty())
|
||||
@@ -815,6 +844,11 @@ public:
|
||||
m_InternalElement = false;
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(size);
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
if(m_StructureStack.empty())
|
||||
@@ -948,6 +982,11 @@ public:
|
||||
m_InternalElement = false;
|
||||
}
|
||||
|
||||
if(IsReading())
|
||||
{
|
||||
VerifyArraySize(size);
|
||||
}
|
||||
|
||||
if(ExportStructure())
|
||||
{
|
||||
if(m_StructureStack.empty())
|
||||
@@ -1516,6 +1555,32 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void VerifyArraySize(uint64_t &count)
|
||||
{
|
||||
uint64_t size = m_Read->GetSize();
|
||||
|
||||
// for streaming, just take 4GB as a 'semi reasonable' upper limit for array sizes
|
||||
if(m_DataStreaming)
|
||||
size = 0xFFFFFFFFU;
|
||||
|
||||
if(count > size)
|
||||
{
|
||||
RDCERR("Reading invalid array or byte buffer - %llu larger than total stream size %llu.",
|
||||
count, size);
|
||||
|
||||
// if we owned the previous stream, delete it
|
||||
if(m_Ownership == Ownership::Stream)
|
||||
delete m_Read;
|
||||
|
||||
// replace our stream with an invalid one so all subsequent reads fail
|
||||
m_Read = new StreamReader(StreamReader::InvalidStream);
|
||||
m_Ownership = Ownership::Stream;
|
||||
|
||||
// set the count to 0
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *m_pUserData = NULL;
|
||||
|
||||
StreamWriter *m_Write = NULL;
|
||||
@@ -1907,3 +1972,12 @@ struct ScopedDeserialiseArray<SerialiserType, byte *>
|
||||
// a member that is a pointer and could be NULL, so needs a hidden 'present'
|
||||
// flag serialised out
|
||||
#define SERIALISE_MEMBER_OPT(obj) ser.SerialiseNullable(#obj, el.obj)
|
||||
|
||||
// simple utility function for inside serialise functions, to check if the serialiser has hit an
|
||||
// error and then bail, without trying to replay anything.
|
||||
#define SERIALISE_CHECK_READ_ERRORS() \
|
||||
if(ser.IsReading() && ser.IsErrored()) \
|
||||
{ \
|
||||
RDCERR("Serialisation failed in '%s'.", ser.GetCurChunkName().c_str()); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
@@ -68,6 +68,8 @@ StreamReader::StreamReader(StreamInvalidType)
|
||||
m_BufferHead = m_BufferBase = NULL;
|
||||
|
||||
m_Ownership = Ownership::Nothing;
|
||||
|
||||
m_HasError = true;
|
||||
}
|
||||
|
||||
StreamReader::StreamReader(Network::Socket *sock, Ownership own)
|
||||
@@ -336,6 +338,8 @@ StreamWriter::StreamWriter(StreamInvalidType)
|
||||
|
||||
m_Ownership = Ownership::Nothing;
|
||||
m_InMemory = false;
|
||||
|
||||
m_HasError = true;
|
||||
}
|
||||
|
||||
StreamWriter::StreamWriter(Network::Socket *sock, Ownership own)
|
||||
|
||||
Reference in New Issue
Block a user