mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-25 07:56:33 +00:00
Add a system for backends to handle device lost/OOM errors and report it
* The UI will become non-functional and the backend will be replaced with a do- nothing one that keeps things alive without needing error bulletproofing everywhere in the real backend.
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#include "Windows/ConstantBufferPreviewer.h"
|
||||
#include "Windows/DebugMessageView.h"
|
||||
#include "Windows/Dialogs/CaptureDialog.h"
|
||||
#include "Windows/Dialogs/CrashDialog.h"
|
||||
#include "Windows/Dialogs/LiveCapture.h"
|
||||
#include "Windows/Dialogs/SettingsDialog.h"
|
||||
#include "Windows/EventBrowser.h"
|
||||
@@ -98,6 +99,98 @@ CaptureContext::CaptureContext(PersistantConfig &cfg) : m_Config(cfg)
|
||||
|
||||
m_MainWindow->LoadInitialLayout();
|
||||
|
||||
m_Replay.SetFatalErrorCallback([this]() {
|
||||
GUIInvoke::call(m_MainWindow, [this]() {
|
||||
RefreshUIStatus({}, true, true);
|
||||
|
||||
ReplayStatus err = GetFatalError();
|
||||
|
||||
QString title;
|
||||
QString text;
|
||||
|
||||
if(err == ReplayStatus::RemoteServerConnectionLost)
|
||||
{
|
||||
QString serverName = Replay().CurrentRemote().Name();
|
||||
|
||||
title = tr("Connection lost to %1").arg(serverName);
|
||||
text =
|
||||
tr("Connection to %1 was lost while analysing capture.\n"
|
||||
"This is most commonly caused by a crash, but that can't be verified and it may be "
|
||||
"a connection issue.")
|
||||
.arg(serverName);
|
||||
}
|
||||
else if(err == ReplayStatus::ReplayDeviceLost)
|
||||
{
|
||||
title = tr("Device Lost error");
|
||||
text =
|
||||
tr("The capture analysis encountered a device lost error. This may be due to an "
|
||||
"application bug, a RenderDoc bug, or insufficient resources on the system to "
|
||||
"analyse the capture.\n\n"
|
||||
"It is recommended that you run your application with API validation enabled, as "
|
||||
"API use errors can cause this kind of problem.");
|
||||
}
|
||||
else if(err == ReplayStatus::ReplayOutOfMemory)
|
||||
{
|
||||
title = tr("Out of GPU memory");
|
||||
text = tr(
|
||||
"While analysing the capture it ran out of GPU memory. This is most likely caused by "
|
||||
"insufficient resources on the system to analyse the capture, which is possible if "
|
||||
"there is memory pressure from other applications or if the capture is heavyweight.");
|
||||
}
|
||||
else
|
||||
{
|
||||
title = tr("Unrecoverable error");
|
||||
text = tr("While analysing the capture we encountered an unrecoverable error:\n\n%1")
|
||||
.arg(QString(ToStr(err)));
|
||||
}
|
||||
|
||||
text +=
|
||||
tr("\n\n"
|
||||
"This error is not recoverable and the analysis cannot continue. The UI will be "
|
||||
"non-functional until the capture is closed and reloaded.\n\n");
|
||||
|
||||
bool add_report = false;
|
||||
|
||||
if(CrashDialog::HasCaptureReady(m_Config))
|
||||
{
|
||||
text += tr(
|
||||
"If you think this may be a RenderDoc bug please click the button below to report it, "
|
||||
"but note that this will require you to upload the capture for reproduction as "
|
||||
"otherwise it is impossible to tell what the problem may be.");
|
||||
|
||||
add_report = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
text += tr("The capture must be saved locally if you want to report this as a bug. ");
|
||||
|
||||
if(Replay().CurrentRemote().IsConnected())
|
||||
{
|
||||
text +=
|
||||
tr("Before closing the capture you can save it to disk and manually report a bug. "
|
||||
"Please include the capture, or else it will be impossible to tell what the "
|
||||
"problem may be.");
|
||||
}
|
||||
else
|
||||
{
|
||||
text += tr("You will need to reconnect to the remote server to save the capture.");
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox mb(QMessageBox::Critical, title, text, QMessageBox::Ok, m_MainWindow);
|
||||
mb.setDefaultButton(QMessageBox::NoButton);
|
||||
QPushButton *report = NULL;
|
||||
if(add_report)
|
||||
report = mb.addButton(tr("Report bug"), QMessageBox::AcceptRole);
|
||||
RDDialog::show(&mb);
|
||||
|
||||
if(mb.clickedButton() == (QAbstractButton *)report)
|
||||
{
|
||||
m_MainWindow->sendErrorReport(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
{
|
||||
QDir dir(ConfigFilePath("extensions"));
|
||||
|
||||
@@ -712,10 +805,11 @@ void CaptureContext::LoadCapture(const rdcstr &captureFile, const ReplayOptions
|
||||
m_LoadInProgress = true;
|
||||
|
||||
if(local)
|
||||
{
|
||||
m_Config.CrashReport_LastOpenedCapture = origFilename;
|
||||
m_Config.Save();
|
||||
}
|
||||
else
|
||||
m_Config.CrashReport_LastOpenedCapture = QString();
|
||||
|
||||
m_Config.Save();
|
||||
|
||||
bool newCapture = (!temporary && !Config().RecentCaptureFiles.contains(origFilename));
|
||||
|
||||
|
||||
@@ -148,6 +148,7 @@ public:
|
||||
bool IsCaptureLocal() override { return m_CaptureLocal; }
|
||||
bool IsCaptureTemporary() override { return m_CaptureTemporary; }
|
||||
bool IsCaptureLoading() override { return m_LoadInProgress; }
|
||||
ReplayStatus GetFatalError() override { return m_Replay.GetFatalError(); }
|
||||
rdcstr GetCaptureFilename() override { return m_CaptureFile; }
|
||||
CaptureModifications GetCaptureModifications() override { return m_CaptureMods; }
|
||||
const FrameDescription &FrameInfo() override { return m_FrameInfo; }
|
||||
|
||||
@@ -1857,6 +1857,13 @@ temporary and treated like any other capture.
|
||||
)");
|
||||
virtual bool IsCaptureLoading() = 0;
|
||||
|
||||
DOCUMENT(R"(If a capture is loaded, return the current fatal error status.
|
||||
|
||||
:return: If a capture is currently loaded, return the fatal error status.
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus GetFatalError() = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieve the filename for the currently loaded capture.
|
||||
|
||||
:return: The filename of the current capture.
|
||||
|
||||
@@ -48,6 +48,8 @@ void ReplayManager::OpenCapture(const QString &capturefile, const ReplayOptions
|
||||
if(m_Running)
|
||||
return;
|
||||
|
||||
m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
// TODO maybe we could expose this choice to the user?
|
||||
int proxyRenderer = -1;
|
||||
|
||||
@@ -296,6 +298,7 @@ void ReplayManager::CancelReplayLoop()
|
||||
void ReplayManager::CloseThread()
|
||||
{
|
||||
m_Running = false;
|
||||
m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
m_RenderCondition.wakeAll();
|
||||
|
||||
@@ -492,6 +495,13 @@ void ReplayManager::run(int proxyRenderer, const QString &capturefile, const Rep
|
||||
|
||||
cmd->method(m_Renderer);
|
||||
|
||||
ReplayStatus err = m_Renderer->GetFatalErrorStatus();
|
||||
if(m_FatalError == ReplayStatus::Succeeded && err != ReplayStatus::Succeeded)
|
||||
{
|
||||
m_FatalError = err;
|
||||
m_FatalErrorCallback();
|
||||
}
|
||||
|
||||
{
|
||||
QMutexLocker lock(&m_TimerLock);
|
||||
m_CommandTimer.invalidate();
|
||||
|
||||
@@ -54,6 +54,8 @@ public:
|
||||
|
||||
bool IsRunning();
|
||||
ReplayStatus GetCreateStatus() { return m_CreateStatus; }
|
||||
void SetFatalErrorCallback(std::function<void()> cb) { m_FatalErrorCallback = cb; }
|
||||
ReplayStatus GetFatalError() { return m_FatalError; }
|
||||
float GetCurrentProcessingTime();
|
||||
QString GetCurrentProcessingTag();
|
||||
// this tagged version is for cases when we might send a request - e.g. to pick a vertex or pixel
|
||||
@@ -136,6 +138,8 @@ private:
|
||||
IRemoteServer *m_Remote = NULL;
|
||||
IRemoteServer *m_OrphanedRemote = NULL;
|
||||
|
||||
std::function<void()> m_FatalErrorCallback;
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
volatile bool m_Running;
|
||||
LambdaThread *m_Thread;
|
||||
ReplayStatus m_CreateStatus = ReplayStatus::Succeeded;
|
||||
|
||||
@@ -96,7 +96,12 @@ void CustomPaintWidget::OnSelectedEventChanged(uint32_t eventId)
|
||||
|
||||
void CustomPaintWidget::OnEventChanged(uint32_t eventId)
|
||||
{
|
||||
// nothing, we only care about capture loaded/closed events
|
||||
// if we've encountered a fatal error recreate the widget and take over painting
|
||||
if(m_Rendering && m_Ctx && m_Ctx->GetFatalError() != ReplayStatus::Succeeded)
|
||||
{
|
||||
RecreateInternalWidget();
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void CustomPaintWidget::update()
|
||||
@@ -130,8 +135,9 @@ void CustomPaintWidget::RecreateInternalWidget()
|
||||
return;
|
||||
}
|
||||
|
||||
// if no capture is loaded, we're not rendering anymore.
|
||||
m_Rendering = m_Rendering && m_Ctx && m_Ctx->IsCaptureLoaded();
|
||||
// if no capture is loaded, or we've encountered a fatal error, we're not rendering anymore.
|
||||
m_Rendering = m_Rendering && m_Ctx && m_Ctx->IsCaptureLoaded() &&
|
||||
m_Ctx->GetFatalError() == ReplayStatus::Succeeded;
|
||||
|
||||
// we need to recreate the widget if it's not matching out rendering state.
|
||||
if(m_Internal == NULL || m_Rendering != m_Internal->IsRendering())
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "ui_CrashDialog.h"
|
||||
|
||||
const qint64 MaxUploadSize = 2250LL * 1024LL * 1024LL;
|
||||
|
||||
CrashDialog::CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::CrashDialog), m_Config(cfg)
|
||||
{
|
||||
@@ -50,11 +52,13 @@ CrashDialog::CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWi
|
||||
m_ReportMetadata = crashReportJSON;
|
||||
|
||||
const bool replayCrash = crashReportJSON[lit("replaycrash")].toUInt() != 0;
|
||||
const bool forceCapture = crashReportJSON[lit("forcecapture")].toUInt() != 0;
|
||||
const bool manualReport =
|
||||
crashReportJSON.contains(lit("manual")) && crashReportJSON[lit("manual")].toUInt() != 0;
|
||||
|
||||
// remove metadata we don't send directly
|
||||
m_ReportMetadata.remove(lit("report"));
|
||||
m_ReportMetadata.remove(lit("forcecapture"));
|
||||
m_ReportMetadata.remove(lit("replaycrash"));
|
||||
|
||||
setStage(ReportStage::FillingDetails);
|
||||
@@ -98,7 +102,7 @@ CrashDialog::CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWi
|
||||
|
||||
cap->Shutdown();
|
||||
|
||||
if(capInfo.size() > 2250LL * 1024LL * 1024LL)
|
||||
if(capInfo.size() > MaxUploadSize)
|
||||
{
|
||||
// capture is too large to upload :(
|
||||
ui->captureFilename->setText(
|
||||
@@ -108,6 +112,13 @@ CrashDialog::CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWi
|
||||
|
||||
ui->capturePreviewFrame->hide();
|
||||
}
|
||||
|
||||
if(forceCapture)
|
||||
{
|
||||
ui->captureUpload->setChecked(true);
|
||||
ui->captureUpload->setEnabled(false);
|
||||
ui->captureUpload->setText(ui->captureUpload->text() + tr(" (required)"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -238,6 +249,13 @@ CrashDialog::~CrashDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool CrashDialog::HasCaptureReady(PersistantConfig &cfg)
|
||||
{
|
||||
QFileInfo capInfo(cfg.CrashReport_LastOpenedCapture);
|
||||
|
||||
return capInfo.exists() && capInfo.size() <= MaxUploadSize;
|
||||
}
|
||||
|
||||
void CrashDialog::showEvent(QShowEvent *)
|
||||
{
|
||||
adjustSize();
|
||||
@@ -299,7 +317,8 @@ void CrashDialog::on_send_clicked()
|
||||
if(result != QMessageBox::Yes)
|
||||
{
|
||||
// uncheck and return back so they can confirm
|
||||
ui->captureUpload->setChecked(false);
|
||||
if(ui->captureUpload->isEnabled())
|
||||
ui->captureUpload->setChecked(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ public:
|
||||
explicit CrashDialog(PersistantConfig &cfg, QVariantMap crashReportJSON, QWidget *parent = 0);
|
||||
~CrashDialog();
|
||||
|
||||
static bool HasCaptureReady(PersistantConfig &cfg);
|
||||
|
||||
private slots:
|
||||
// automatic slots
|
||||
void on_send_clicked();
|
||||
|
||||
@@ -1828,16 +1828,6 @@ void MainWindow::messageCheck()
|
||||
}
|
||||
|
||||
GUIInvoke::call(this, [this, disconnected, msgs] {
|
||||
// if we just got disconnected while replaying a capture, alert the user.
|
||||
if(disconnected)
|
||||
{
|
||||
RDDialog::critical(this, tr("Remote server disconnected"),
|
||||
tr("Remote server disconnected during replaying of this capture.\n"
|
||||
"The replay will now be non-functional. To restore you will have "
|
||||
"to close the capture, allow "
|
||||
"RenderDoc to reconnect and load the capture again"));
|
||||
}
|
||||
|
||||
if(m_Ctx.Replay().CurrentRemote().IsValid() &&
|
||||
!m_Ctx.Replay().CurrentRemote().IsServerRunning())
|
||||
contextChooser->setIcon(Icons::cross());
|
||||
@@ -2841,6 +2831,11 @@ void MainWindow::on_action_Resource_Inspector_triggered()
|
||||
}
|
||||
|
||||
void MainWindow::on_action_Send_Error_Report_triggered()
|
||||
{
|
||||
sendErrorReport(false);
|
||||
}
|
||||
|
||||
void MainWindow::sendErrorReport(bool forceCaptureInclusion)
|
||||
{
|
||||
rdcstr report;
|
||||
RENDERDOC_CreateBugReport(RENDERDOC_GetLogFile(), "", report);
|
||||
@@ -2851,6 +2846,7 @@ void MainWindow::on_action_Send_Error_Report_triggered()
|
||||
json[lit("gitcommit")] = QString::fromLatin1(RENDERDOC_GetCommitHash());
|
||||
json[lit("replaycrash")] = 1;
|
||||
json[lit("manual")] = 1;
|
||||
json[lit("forcecapture")] = forceCaptureInclusion ? 1 : 0;
|
||||
json[lit("report")] = (QString)report;
|
||||
|
||||
CrashDialog crash(m_Ctx.Config(), json, this);
|
||||
|
||||
@@ -94,6 +94,8 @@ public:
|
||||
|
||||
void LoadInitialLayout();
|
||||
|
||||
void sendErrorReport(bool forceCaptureInclusion);
|
||||
|
||||
void setProgress(float val);
|
||||
void setRemoteHost(int hostIdx);
|
||||
void takeCaptureOwnership() { m_OwnTempCapture = true; }
|
||||
|
||||
@@ -414,6 +414,7 @@ struct CaptureContextInvoker : ObjectForwarder<ICaptureContext>
|
||||
virtual bool IsCaptureLocal() override { return m_Obj.IsCaptureLocal(); }
|
||||
virtual bool IsCaptureTemporary() override { return m_Obj.IsCaptureTemporary(); }
|
||||
virtual bool IsCaptureLoading() override { return m_Obj.IsCaptureLoading(); }
|
||||
virtual ReplayStatus GetFatalError() override { return m_Obj.GetFatalError(); }
|
||||
virtual rdcstr GetCaptureFilename() override { return m_Obj.GetCaptureFilename(); }
|
||||
virtual CaptureModifications GetCaptureModifications() override
|
||||
{
|
||||
|
||||
@@ -175,6 +175,8 @@ set(sources
|
||||
replay/app_api.cpp
|
||||
replay/basic_types_tests.cpp
|
||||
replay/capture_options.cpp
|
||||
replay/dummy_driver.cpp
|
||||
replay/dummy_driver.h
|
||||
replay/renderdoc_serialise.inl
|
||||
replay/capture_file.cpp
|
||||
replay/entry_points.cpp
|
||||
|
||||
@@ -762,6 +762,22 @@ newly generated messages will be returned after that.
|
||||
)");
|
||||
virtual rdcarray<DebugMessage> GetDebugMessages() = 0;
|
||||
|
||||
DOCUMENT(R"(Poll for the current status of the replay.
|
||||
|
||||
This function can be used to monitor to see if a fatal error has been encountered and react
|
||||
appropriately, such as by displaying a message to the user. The replay controller interface should
|
||||
remain stable and return null/empty data for the most part, but it's recommended for maximum
|
||||
stability to stop using the controller when a fatal error is encountered.
|
||||
|
||||
If there has been no error, this will return :data:`ReplayStatus.Succeeded`. If there has been an
|
||||
error this will return the error code every time, it will not be 'consumed' so it's safe to have
|
||||
multiple things checking it.
|
||||
|
||||
:return: The current fatal error status.
|
||||
:rtype: ReplayStatus
|
||||
)");
|
||||
virtual ReplayStatus GetFatalErrorStatus() = 0;
|
||||
|
||||
DOCUMENT(R"(Retrieve a list of entry points for a shader.
|
||||
|
||||
If the given ID doesn't specify a shader, an empty list will be return. On some APIs, the list will
|
||||
|
||||
@@ -91,6 +91,9 @@ rdcstr DoStringise(const ReplayStatus &el)
|
||||
"Failed to install Android remote server for unknown reasons");
|
||||
STRINGISE_ENUM_CLASS_NAMED(AndroidAPKVerifyFailed,
|
||||
"Failed to verify installed Android remote server");
|
||||
STRINGISE_ENUM_CLASS_NAMED(RemoteServerConnectionLost, "Connection lost to remote server");
|
||||
STRINGISE_ENUM_CLASS_NAMED(ReplayOutOfMemory, "Encountered GPU out of memory error");
|
||||
STRINGISE_ENUM_CLASS_NAMED(ReplayDeviceLost, "Encountered a GPU device lost error");
|
||||
}
|
||||
END_ENUM_STRINGISE();
|
||||
}
|
||||
|
||||
@@ -3656,6 +3656,18 @@ a remote server.
|
||||
.. data:: AndroidAPKVerifyFailed
|
||||
|
||||
Failed to install Android remote server.
|
||||
|
||||
.. data:: RemoteServerConnectionLost
|
||||
|
||||
While replaying on a remote server, the connection was lost.
|
||||
|
||||
.. data:: ReplayOutOfMemory
|
||||
|
||||
While replaying, a GPU out of memory error was encountered.
|
||||
|
||||
.. data:: ReplayDeviceLost
|
||||
|
||||
While replaying a device lost fatal error was encountered.
|
||||
)");
|
||||
enum class ReplayStatus : uint32_t
|
||||
{
|
||||
@@ -3684,6 +3696,9 @@ enum class ReplayStatus : uint32_t
|
||||
AndroidAPKFolderNotFound,
|
||||
AndroidAPKInstallFailed,
|
||||
AndroidAPKVerifyFailed,
|
||||
RemoteServerConnectionLost,
|
||||
ReplayOutOfMemory,
|
||||
ReplayDeviceLost,
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_ENUM(ReplayStatus);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "common/dds_readwrite.h"
|
||||
#include "core/core.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "stb/stb_image.h"
|
||||
@@ -72,12 +73,27 @@ public:
|
||||
|
||||
virtual ~ImageViewer()
|
||||
{
|
||||
m_Proxy->Shutdown();
|
||||
m_Proxy = NULL;
|
||||
SAFE_DELETE(m_File);
|
||||
if(m_Proxy)
|
||||
{
|
||||
m_Proxy->Shutdown();
|
||||
m_Proxy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsRemoteProxy() { return true; }
|
||||
ReplayStatus FatalErrorCheck()
|
||||
{
|
||||
// check for errors on the underlying proxy driver
|
||||
return m_Proxy->FatalErrorCheck();
|
||||
}
|
||||
IReplayDriver *MakeDummyDriver()
|
||||
{
|
||||
IReplayDriver *ret = new DummyDriver(this, {});
|
||||
// lose our structured file reference
|
||||
m_File = NULL;
|
||||
return ret;
|
||||
}
|
||||
void Shutdown() { delete this; }
|
||||
// pass through necessary operations to proxy
|
||||
rdcarray<WindowingSystem> GetSupportedWindowSystems()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "replay_proxy.h"
|
||||
#include <list>
|
||||
#include "lz4/lz4.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "serialise/lz4io.h"
|
||||
|
||||
template <>
|
||||
@@ -128,25 +129,37 @@ rdcstr DoStringise(const ReplayProxyPacket &el)
|
||||
// begin serialising a return value. We begin a chunk here in either the writing or reading case
|
||||
// since this chunk is used purely to send/receive the return value and is fully handled within the
|
||||
// function.
|
||||
#define SERIALISE_RETURN(retval) \
|
||||
{ \
|
||||
ReturnSerialiser &ser = retser; \
|
||||
PACKET_HEADER(packet); \
|
||||
SERIALISE_ELEMENT(retval); \
|
||||
GET_SERIALISER.Serialise("packet"_lit, packet); \
|
||||
ser.EndChunk(); \
|
||||
CheckError(packet, expectedPacket); \
|
||||
#define SERIALISE_RETURN(retval) \
|
||||
{ \
|
||||
ReplayStatus fatalStatus = ReplayStatus::Succeeded; \
|
||||
if(m_RemoteServer) \
|
||||
fatalStatus = m_Remote->FatalErrorCheck(); \
|
||||
ReturnSerialiser &ser = retser; \
|
||||
PACKET_HEADER(packet); \
|
||||
SERIALISE_ELEMENT(retval); \
|
||||
GET_SERIALISER.Serialise("fatalStatus"_lit, fatalStatus); \
|
||||
GET_SERIALISER.Serialise("packet"_lit, packet); \
|
||||
ser.EndChunk(); \
|
||||
if(fatalStatus != ReplayStatus::Succeeded && m_FatalError == ReplayStatus::Succeeded) \
|
||||
m_FatalError = fatalStatus; \
|
||||
CheckError(packet, expectedPacket); \
|
||||
}
|
||||
|
||||
// similar to the above, but for void functions that don't return anything. We still want to check
|
||||
// that both sides of the communication are on the same page.
|
||||
#define SERIALISE_RETURN_VOID() \
|
||||
{ \
|
||||
ReturnSerialiser &ser = retser; \
|
||||
PACKET_HEADER(packet); \
|
||||
SERIALISE_ELEMENT(packet); \
|
||||
ser.EndChunk(); \
|
||||
CheckError(packet, expectedPacket); \
|
||||
#define SERIALISE_RETURN_VOID() \
|
||||
{ \
|
||||
ReplayStatus fatalStatus = ReplayStatus::Succeeded; \
|
||||
if(m_RemoteServer) \
|
||||
fatalStatus = m_Remote->FatalErrorCheck(); \
|
||||
ReturnSerialiser &ser = retser; \
|
||||
PACKET_HEADER(packet); \
|
||||
SERIALISE_ELEMENT(packet); \
|
||||
GET_SERIALISER.Serialise("fatalStatus"_lit, fatalStatus); \
|
||||
ser.EndChunk(); \
|
||||
if(fatalStatus != ReplayStatus::Succeeded && m_FatalError == ReplayStatus::Succeeded) \
|
||||
m_FatalError = fatalStatus; \
|
||||
CheckError(packet, expectedPacket); \
|
||||
}
|
||||
|
||||
// defines the area where we're executing on the remote host. To avoid timeouts, the remote side
|
||||
@@ -2766,8 +2779,49 @@ void ReplayProxy::RemoteExecutionThreadEntry()
|
||||
}
|
||||
}
|
||||
|
||||
ReplayStatus ReplayProxy::FatalErrorCheck()
|
||||
{
|
||||
// this isn't proxied since it's called at relatively high frequency. Whenever we proxy a
|
||||
// function, we also return the the remote side's status
|
||||
if(m_IsErrored)
|
||||
{
|
||||
// if we're error'd due to a network issue (i.e. the other side crashed and disconnected) we
|
||||
// won't have a status, set a generic one
|
||||
if(m_FatalError == ReplayStatus::Succeeded)
|
||||
m_FatalError = ReplayStatus::RemoteServerConnectionLost;
|
||||
|
||||
return m_FatalError;
|
||||
}
|
||||
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
IReplayDriver *ReplayProxy::MakeDummyDriver()
|
||||
{
|
||||
// gather up the shaders we've allocated to pass to the dummy driver
|
||||
rdcarray<ShaderReflection *> shaders;
|
||||
for(auto it = m_ShaderReflectionCache.begin(); it != m_ShaderReflectionCache.end(); ++it)
|
||||
shaders.push_back(it->second);
|
||||
m_ShaderReflectionCache.clear();
|
||||
|
||||
IReplayDriver *dummy = new DummyDriver(this, shaders);
|
||||
|
||||
// the dummy driver now owns the file, remove our reference
|
||||
m_StructuredFile = NULL;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
bool ReplayProxy::CheckError(ReplayProxyPacket receivedPacket, ReplayProxyPacket expectedPacket)
|
||||
{
|
||||
if(m_FatalError != ReplayStatus::Succeeded)
|
||||
{
|
||||
RDCERR("Fatal error detected while processing %s: %s", ToStr(expectedPacket).c_str(),
|
||||
ToStr(m_FatalError).c_str());
|
||||
m_IsErrored = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_Writer.IsErrored() || m_Reader.IsErrored() || m_IsErrored)
|
||||
{
|
||||
RDCERR("Error during processing of %s", ToStr(expectedPacket).c_str());
|
||||
|
||||
@@ -103,6 +103,8 @@ enum ReplayProxyPacket
|
||||
|
||||
eReplayProxy_ContinueDebug,
|
||||
eReplayProxy_FreeDebugger,
|
||||
|
||||
eReplayProxy_FatalErrorCheck,
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_ENUM(ReplayProxyPacket);
|
||||
@@ -140,6 +142,8 @@ public:
|
||||
void RemoteExecutionThreadEntry();
|
||||
|
||||
bool IsRemoteProxy() { return !m_RemoteServer; }
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
void Shutdown() { delete this; }
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
@@ -694,6 +698,7 @@ private:
|
||||
Threading::ThreadHandle m_RemoteExecutionThread = 0;
|
||||
|
||||
bool m_IsErrored = false;
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
FrameRecord m_FrameRecord;
|
||||
APIProperties m_APIProps;
|
||||
|
||||
@@ -601,6 +601,7 @@ private:
|
||||
SDFile *m_StoredStructuredData;
|
||||
|
||||
rdcarray<DebugMessage> m_DebugMessages;
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
rdcarray<FrameDescription> m_CapturedFrames;
|
||||
rdcarray<ActionDescription *> m_Actions;
|
||||
@@ -660,10 +661,12 @@ public:
|
||||
void UnlockForChunkRemoval();
|
||||
|
||||
SDFile *GetStructuredFile() { return m_StructuredFile; }
|
||||
void DetachStructuredFile() { m_StoredStructuredData = m_StructuredFile = NULL; }
|
||||
uint64_t GetTimeBase() { return m_TimeBase; }
|
||||
double GetTimeFrequency() { return m_TimeFrequency; }
|
||||
void FirstFrame(IDXGISwapper *swapper);
|
||||
|
||||
ReplayStatus FatalErrorCheck() { return m_FatalError; }
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
void AddDebugMessage(DebugMessage msg);
|
||||
void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "maths/camera.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "maths/matrix.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "d3d11_context.h"
|
||||
@@ -77,10 +78,31 @@ void D3D11Replay::Shutdown()
|
||||
m_ProxyResources[i]->Release();
|
||||
m_ProxyResources.clear();
|
||||
|
||||
m_RealState.state.Clear();
|
||||
|
||||
// explicitly delete the device, as all the replay resources created will be keeping refs on it
|
||||
delete m_pDevice;
|
||||
}
|
||||
|
||||
ReplayStatus D3D11Replay::FatalErrorCheck()
|
||||
{
|
||||
return m_pDevice->FatalErrorCheck();
|
||||
}
|
||||
|
||||
IReplayDriver *D3D11Replay::MakeDummyDriver()
|
||||
{
|
||||
// gather up the shaders we've allocated to pass to the dummy driver
|
||||
rdcarray<ShaderReflection *> shaders;
|
||||
WrappedID3D11Shader<ID3D11ComputeShader>::GetReflections(shaders);
|
||||
|
||||
IReplayDriver *dummy = new DummyDriver(this, shaders);
|
||||
|
||||
// the dummy driver now owns the file, remove our reference
|
||||
m_pDevice->DetachStructuredFile();
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
void D3D11Replay::CreateResources(IDXGIFactory *factory)
|
||||
{
|
||||
bool wrapped =
|
||||
|
||||
@@ -109,6 +109,9 @@ public:
|
||||
bool IsRemoteProxy() { return m_Proxy; }
|
||||
void Shutdown();
|
||||
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
|
||||
void CreateResources(IDXGIFactory *factory);
|
||||
void DestroyResources();
|
||||
|
||||
|
||||
@@ -1041,6 +1041,8 @@ public:
|
||||
DXBC::DXBCContainer *m_DXBCFile;
|
||||
ShaderReflection *m_Details;
|
||||
ShaderBindpointMapping m_Mapping;
|
||||
|
||||
friend class WrappedShader;
|
||||
};
|
||||
|
||||
static std::map<ResourceId, ShaderEntry *> m_ShaderList;
|
||||
@@ -1094,6 +1096,17 @@ public:
|
||||
return m_ShaderList[m_ID]->GetMapping();
|
||||
}
|
||||
|
||||
static void GetReflections(rdcarray<ShaderReflection *> &refls)
|
||||
{
|
||||
SCOPED_LOCK(m_ShaderListLock);
|
||||
refls.clear();
|
||||
for(auto it = m_ShaderList.begin(); it != m_ShaderList.end(); ++it)
|
||||
{
|
||||
refls.push_back(it->second->m_Details);
|
||||
it->second->m_Details = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceId m_ID;
|
||||
};
|
||||
|
||||
@@ -667,6 +667,7 @@ private:
|
||||
rdcarray<TempMem *> m_ThreadTempMem;
|
||||
|
||||
rdcarray<DebugMessage> m_DebugMessages;
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
uint64_t m_TimeBase = 0;
|
||||
double m_TimeFrequency = 1.0f;
|
||||
@@ -799,7 +800,7 @@ public:
|
||||
void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, rdcstr d);
|
||||
void AddDebugMessage(const DebugMessage &msg);
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
|
||||
ReplayStatus FatalErrorCheck() { return m_FatalError; }
|
||||
ResourceDescription &GetResourceDesc(ResourceId id);
|
||||
void AddResource(ResourceId id, ResourceType type, const char *defaultNamePrefix);
|
||||
void DerivedResource(ResourceId parent, ResourceId child);
|
||||
@@ -926,6 +927,7 @@ public:
|
||||
m_State = CaptureState::StructuredExport;
|
||||
}
|
||||
SDFile *GetStructuredFile() { return m_StructuredFile; }
|
||||
void DetachStructuredFile() { m_StoredStructuredData = m_StructuredFile = NULL; }
|
||||
uint64_t GetTimeBase() { return m_TimeBase; }
|
||||
double GetTimeFrequency() { return m_TimeFrequency; }
|
||||
// interface for DXGI
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "maths/camera.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "maths/matrix.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "d3d12_command_queue.h"
|
||||
@@ -114,6 +115,25 @@ void D3D12Replay::Initialise(IDXGIFactory1 *factory)
|
||||
}
|
||||
}
|
||||
|
||||
ReplayStatus D3D12Replay::FatalErrorCheck()
|
||||
{
|
||||
return m_pDevice->FatalErrorCheck();
|
||||
}
|
||||
|
||||
IReplayDriver *D3D12Replay::MakeDummyDriver()
|
||||
{
|
||||
// gather up the shaders we've allocated to pass to the dummy driver
|
||||
rdcarray<ShaderReflection *> shaders;
|
||||
WrappedID3D12Shader::GetReflections(shaders);
|
||||
|
||||
IReplayDriver *dummy = new DummyDriver(this, shaders);
|
||||
|
||||
// the dummy driver now owns the file, remove our reference
|
||||
m_pDevice->DetachStructuredFile();
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
void D3D12Replay::CreateResources()
|
||||
{
|
||||
m_DebugManager = new D3D12DebugManager(m_pDevice);
|
||||
|
||||
@@ -84,6 +84,9 @@ public:
|
||||
void Initialise(IDXGIFactory1 *factory);
|
||||
void Shutdown();
|
||||
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
|
||||
void CreateResources();
|
||||
void DestroyResources();
|
||||
DriverInformation GetDriverInfo() { return m_DriverInfo; }
|
||||
|
||||
@@ -744,6 +744,16 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
static void GetReflections(rdcarray<ShaderReflection *> &refls)
|
||||
{
|
||||
refls.clear();
|
||||
for(auto it = m_Shaders.begin(); it != m_Shaders.end(); ++it)
|
||||
{
|
||||
refls.push_back(it->second->m_Details);
|
||||
it->second->m_Details = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void GetShaderExtSlot(uint32_t &slot, uint32_t &space)
|
||||
{
|
||||
slot = m_ShaderExtSlot;
|
||||
|
||||
@@ -111,11 +111,12 @@ private:
|
||||
|
||||
GLPlatform &m_Platform;
|
||||
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
rdcarray<DebugMessage> m_DebugMessages;
|
||||
template <typename SerialiserType>
|
||||
void Serialise_DebugMessages(SerialiserType &ser);
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
|
||||
ReplayStatus FatalErrorCheck() { return m_FatalError; }
|
||||
rdcstr m_DebugMsgContext;
|
||||
|
||||
bool m_SuppressDebugMessages;
|
||||
@@ -633,6 +634,7 @@ public:
|
||||
m_State = CaptureState::StructuredExport;
|
||||
}
|
||||
SDFile *GetStructuredFile() { return m_StructuredFile; }
|
||||
void DetachStructuredFile() { m_StoredStructuredData = m_StructuredFile = NULL; }
|
||||
void SetFetchCounters(bool in) { m_FetchCounters = in; };
|
||||
void SetDebugMsgContext(const rdcstr &context) { m_DebugMsgContext = context; }
|
||||
void AddDebugMessage(DebugMessage msg)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "driver/ihv/arm/arm_counters.h"
|
||||
#include "driver/ihv/intel/intel_gl_counters.h"
|
||||
#include "maths/matrix.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "gl_driver.h"
|
||||
@@ -86,6 +87,29 @@ void GLReplay::Shutdown()
|
||||
delete m_pDriver;
|
||||
}
|
||||
|
||||
ReplayStatus GLReplay::FatalErrorCheck()
|
||||
{
|
||||
return m_pDriver->FatalErrorCheck();
|
||||
}
|
||||
|
||||
IReplayDriver *GLReplay::MakeDummyDriver()
|
||||
{
|
||||
// gather up the shaders we've allocated to pass to the dummy driver
|
||||
rdcarray<ShaderReflection *> shaders;
|
||||
for(auto it = m_pDriver->m_Shaders.begin(); it != m_pDriver->m_Shaders.end(); it++)
|
||||
{
|
||||
shaders.push_back(it->second.reflection);
|
||||
it->second.reflection = NULL;
|
||||
}
|
||||
|
||||
IReplayDriver *dummy = new DummyDriver(this, shaders);
|
||||
|
||||
// the dummy driver now owns the file, remove our reference
|
||||
m_pDriver->DetachStructuredFile();
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
ReplayStatus GLReplay::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
MakeCurrentReplayContext(&m_ReplayCtx);
|
||||
|
||||
@@ -115,6 +115,9 @@ public:
|
||||
bool IsRemoteProxy() { return m_Proxy; }
|
||||
void Shutdown();
|
||||
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
|
||||
DriverInformation GetDriverInfo() { return m_DriverInfo; }
|
||||
rdcarray<GPUDevice> GetAvailableGPUs();
|
||||
APIProperties GetAPIProperties();
|
||||
|
||||
@@ -286,10 +286,11 @@ private:
|
||||
void Serialise_DebugMessages(SerialiserType &ser);
|
||||
|
||||
void ProcessDebugMessage(DebugMessage &DebugMessages);
|
||||
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
void AddDebugMessage(DebugMessage msg);
|
||||
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
ReplayStatus FatalErrorCheck() { return m_FatalError; }
|
||||
CaptureState m_State;
|
||||
bool m_AppControlledCapture = false;
|
||||
|
||||
@@ -1040,6 +1041,7 @@ public:
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
|
||||
SDFile *GetStructuredFile() { return m_StructuredFile; }
|
||||
void DetachStructuredFile() { m_StoredStructuredData = m_StructuredFile = NULL; }
|
||||
const APIEvent &GetEvent(uint32_t eventId);
|
||||
uint32_t GetMaxEID() { return m_Events.back().eventId; }
|
||||
const ActionDescription *GetAction(uint32_t eventId);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "driver/shaders/spirv/spirv_compile.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "maths/matrix.h"
|
||||
#include "replay/dummy_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "vk_core.h"
|
||||
@@ -83,6 +84,34 @@ void VulkanReplay::Shutdown()
|
||||
delete m_pDriver;
|
||||
}
|
||||
|
||||
ReplayStatus VulkanReplay::FatalErrorCheck()
|
||||
{
|
||||
return m_pDriver->FatalErrorCheck();
|
||||
}
|
||||
|
||||
IReplayDriver *VulkanReplay::MakeDummyDriver()
|
||||
{
|
||||
// gather up the shaders we've allocated to pass to the dummy driver
|
||||
rdcarray<ShaderReflection *> shaders;
|
||||
for(auto it = m_pDriver->m_CreationInfo.m_ShaderModule.begin();
|
||||
it != m_pDriver->m_CreationInfo.m_ShaderModule.end(); it++)
|
||||
{
|
||||
for(auto reflit = it->second.m_Reflections.begin(); reflit != it->second.m_Reflections.end();
|
||||
++reflit)
|
||||
{
|
||||
shaders.push_back(reflit->second.refl);
|
||||
reflit->second.refl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
IReplayDriver *dummy = new DummyDriver(this, shaders);
|
||||
|
||||
// the dummy driver now owns the file, remove our reference
|
||||
m_pDriver->DetachStructuredFile();
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
rdcarray<GPUDevice> VulkanReplay::GetAvailableGPUs()
|
||||
{
|
||||
rdcarray<GPUDevice> ret;
|
||||
|
||||
@@ -267,6 +267,9 @@ public:
|
||||
bool IsRemoteProxy() { return m_Proxy; }
|
||||
void Shutdown();
|
||||
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
|
||||
void CreateResources();
|
||||
void DestroyResources();
|
||||
|
||||
|
||||
@@ -242,6 +242,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="os\win32\dia2_stubs.h" />
|
||||
<ClInclude Include="os\win32\win32_specific.h" />
|
||||
<ClInclude Include="replay\dummy_driver.h" />
|
||||
<ClInclude Include="replay\replay_driver.h" />
|
||||
<ClInclude Include="replay\replay_controller.h" />
|
||||
<ClInclude Include="serialise\codecs\vk_cpp_codec_common.h" />
|
||||
@@ -656,6 +657,7 @@
|
||||
<ClCompile Include="replay\basic_types_tests.cpp" />
|
||||
<ClCompile Include="replay\capture_file.cpp" />
|
||||
<ClCompile Include="replay\capture_options.cpp" />
|
||||
<ClCompile Include="replay\dummy_driver.cpp" />
|
||||
<ClCompile Include="replay\entry_points.cpp" />
|
||||
<ClCompile Include="replay\replay_driver.cpp" />
|
||||
<ClCompile Include="replay\replay_output.cpp" />
|
||||
|
||||
@@ -570,6 +570,9 @@
|
||||
<ClInclude Include="3rdparty\md5\md5.h">
|
||||
<Filter>3rdparty\md5</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="replay\dummy_driver.h">
|
||||
<Filter>Replay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="maths\camera.cpp">
|
||||
@@ -986,6 +989,9 @@
|
||||
<ClCompile Include="3rdparty\md5\md5.c">
|
||||
<Filter>3rdparty\md5</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="replay\dummy_driver.cpp">
|
||||
<Filter>Replay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="os\win32\comexport.def">
|
||||
|
||||
@@ -0,0 +1,505 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "dummy_driver.h"
|
||||
|
||||
DummyDriver::DummyDriver(IReplayDriver *original, const rdcarray<ShaderReflection *> &shaders)
|
||||
{
|
||||
m_Shaders = shaders;
|
||||
|
||||
m_Props = original->GetAPIProperties();
|
||||
m_Resources = original->GetResources();
|
||||
m_Buffers = original->GetBuffers();
|
||||
m_Textures = original->GetTextures();
|
||||
m_FrameRecord = original->GetFrameRecord();
|
||||
m_SDFile = original->GetStructuredFile();
|
||||
m_TargetEncodings = original->GetTargetShaderEncodings();
|
||||
m_DriverInfo = original->GetDriverInfo();
|
||||
|
||||
m_Proxy = original->IsRemoteProxy();
|
||||
m_GPUs = original->GetAvailableGPUs();
|
||||
m_WindowSystems = original->GetSupportedWindowSystems();
|
||||
m_CustomEncodings = original->GetCustomShaderEncodings();
|
||||
}
|
||||
|
||||
DummyDriver::~DummyDriver()
|
||||
{
|
||||
// we own the shaders
|
||||
for(ShaderReflection *refl : m_Shaders)
|
||||
delete refl;
|
||||
|
||||
// and we own the structured file
|
||||
delete m_SDFile;
|
||||
}
|
||||
|
||||
void DummyDriver::Shutdown()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
APIProperties DummyDriver::GetAPIProperties()
|
||||
{
|
||||
return m_Props;
|
||||
}
|
||||
|
||||
rdcarray<ResourceDescription> DummyDriver::GetResources()
|
||||
{
|
||||
return m_Resources;
|
||||
}
|
||||
|
||||
rdcarray<BufferDescription> DummyDriver::GetBuffers()
|
||||
{
|
||||
return m_Buffers;
|
||||
}
|
||||
|
||||
BufferDescription DummyDriver::GetBuffer(ResourceId id)
|
||||
{
|
||||
for(const BufferDescription &buf : m_Buffers)
|
||||
{
|
||||
if(buf.resourceId == id)
|
||||
return buf;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
rdcarray<TextureDescription> DummyDriver::GetTextures()
|
||||
{
|
||||
return m_Textures;
|
||||
}
|
||||
|
||||
TextureDescription DummyDriver::GetTexture(ResourceId id)
|
||||
{
|
||||
for(const TextureDescription &tex : m_Textures)
|
||||
{
|
||||
if(tex.resourceId == id)
|
||||
return tex;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
rdcarray<DebugMessage> DummyDriver::GetDebugMessages()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
rdcarray<ShaderEntryPoint> DummyDriver::GetShaderEntryPoints(ResourceId shader)
|
||||
{
|
||||
return {{"main", ShaderStage::Vertex}};
|
||||
}
|
||||
|
||||
ShaderReflection *DummyDriver::GetShader(ResourceId pipeline, ResourceId shader,
|
||||
ShaderEntryPoint entry)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rdcarray<rdcstr> DummyDriver::GetDisassemblyTargets(bool withPipeline)
|
||||
{
|
||||
return {"Disassembly"};
|
||||
}
|
||||
|
||||
rdcstr DummyDriver::DisassembleShader(ResourceId pipeline, const ShaderReflection *refl,
|
||||
const rdcstr &target)
|
||||
{
|
||||
return "; No disassembly available due to unrecoverable error analysing capture.";
|
||||
}
|
||||
|
||||
rdcarray<EventUsage> DummyDriver::GetUsage(ResourceId id)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void DummyDriver::SetPipelineStates(D3D11Pipe::State *d3d11, D3D12Pipe::State *d3d12,
|
||||
GLPipe::State *gl, VKPipe::State *vk)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::SavePipelineState(uint32_t eventId)
|
||||
{
|
||||
}
|
||||
|
||||
FrameRecord DummyDriver::GetFrameRecord()
|
||||
{
|
||||
return m_FrameRecord;
|
||||
}
|
||||
|
||||
ReplayStatus DummyDriver::ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers)
|
||||
{
|
||||
return ReplayStatus::APIReplayFailed;
|
||||
}
|
||||
|
||||
void DummyDriver::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
|
||||
{
|
||||
}
|
||||
|
||||
SDFile *DummyDriver::GetStructuredFile()
|
||||
{
|
||||
return m_SDFile;
|
||||
}
|
||||
|
||||
rdcarray<uint32_t> DummyDriver::GetPassEvents(uint32_t eventId)
|
||||
{
|
||||
return {eventId};
|
||||
}
|
||||
|
||||
void DummyDriver::InitPostVSBuffers(uint32_t eventId)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::InitPostVSBuffers(const rdcarray<uint32_t> &passEvents)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId DummyDriver::GetLiveID(ResourceId id)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
MeshFormat DummyDriver::GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID,
|
||||
MeshDataStage stage)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void DummyDriver::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData)
|
||||
{
|
||||
retData.clear();
|
||||
}
|
||||
|
||||
void DummyDriver::GetTextureData(ResourceId tex, const Subresource &sub,
|
||||
const GetTextureDataParams ¶ms, bytebuf &data)
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
void DummyDriver::BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source,
|
||||
const rdcstr &entry, const ShaderCompileFlags &compileFlags,
|
||||
ShaderStage type, ResourceId &id, rdcstr &errors)
|
||||
{
|
||||
id = ResourceId();
|
||||
errors = "Unrecoverable error encountered while analysing capture";
|
||||
}
|
||||
|
||||
rdcarray<ShaderEncoding> DummyDriver::GetTargetShaderEncodings()
|
||||
{
|
||||
return {ShaderEncoding::HLSL, ShaderEncoding::GLSL};
|
||||
}
|
||||
|
||||
void DummyDriver::ReplaceResource(ResourceId from, ResourceId to)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::RemoveReplacement(ResourceId id)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::FreeTargetResource(ResourceId id)
|
||||
{
|
||||
}
|
||||
|
||||
rdcarray<GPUCounter> DummyDriver::EnumerateCounters()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
CounterDescription DummyDriver::DescribeCounter(GPUCounter counterID)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
rdcarray<CounterResult> DummyDriver::FetchCounters(const rdcarray<GPUCounter> &counterID)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void DummyDriver::FillCBufferVariables(ResourceId pipeline, ResourceId shader, rdcstr entryPoint,
|
||||
uint32_t cbufSlot, rdcarray<ShaderVariable> &outvars,
|
||||
const bytebuf &data)
|
||||
{
|
||||
outvars.clear();
|
||||
}
|
||||
|
||||
rdcarray<PixelModification> DummyDriver::PixelHistory(rdcarray<EventUsage> events,
|
||||
ResourceId target, uint32_t x, uint32_t y,
|
||||
const Subresource &sub, CompType typeCast)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
ShaderDebugTrace *DummyDriver::DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid,
|
||||
uint32_t idx, uint32_t view)
|
||||
{
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *DummyDriver::DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
|
||||
uint32_t primitive)
|
||||
{
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
ShaderDebugTrace *DummyDriver::DebugThread(uint32_t eventId,
|
||||
const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid)
|
||||
{
|
||||
return new ShaderDebugTrace;
|
||||
}
|
||||
|
||||
rdcarray<ShaderDebugState> DummyDriver::ContinueDebug(ShaderDebugger *debugger)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void DummyDriver::FreeDebugger(ShaderDebugger *debugger)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId DummyDriver::RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay,
|
||||
uint32_t eventId, const rdcarray<uint32_t> &passEvents)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
bool DummyDriver::IsRenderOutput(ResourceId id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DummyDriver::FileChanged()
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::NeedRemapForFetch(const ResourceFormat &format)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DriverInformation DummyDriver::GetDriverInfo()
|
||||
{
|
||||
return m_DriverInfo;
|
||||
}
|
||||
|
||||
rdcarray<GPUDevice> DummyDriver::GetAvailableGPUs()
|
||||
{
|
||||
return m_GPUs;
|
||||
}
|
||||
|
||||
bool DummyDriver::IsRemoteProxy()
|
||||
{
|
||||
return m_Proxy;
|
||||
}
|
||||
|
||||
ReplayStatus DummyDriver::FatalErrorCheck()
|
||||
{
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
IReplayDriver *DummyDriver::MakeDummyDriver()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rdcarray<WindowingSystem> DummyDriver::GetSupportedWindowSystems()
|
||||
{
|
||||
rdcarray<WindowingSystem> ret;
|
||||
#if ENABLED(RDOC_LINUX)
|
||||
|
||||
#if ENABLED(RDOC_XLIB)
|
||||
ret.push_back(WindowingSystem::Xlib);
|
||||
#endif
|
||||
|
||||
#if ENABLED(RDOC_XCB)
|
||||
ret.push_back(WindowingSystem::XCB);
|
||||
#endif
|
||||
|
||||
#if ENABLED(RDOC_WAYLAND)
|
||||
ret.push_back(WindowingSystem::Wayland);
|
||||
#endif
|
||||
|
||||
#elif ENABLED(RDOC_WIN32)
|
||||
|
||||
ret.push_back(WindowingSystem::Win32);
|
||||
|
||||
#elif ENABLED(RDOC_ANDROID)
|
||||
|
||||
ret.push_back(WindowingSystem::Android);
|
||||
|
||||
#elif ENABLED(RDOC_APPLE)
|
||||
|
||||
ret.push_back(WindowingSystem::MacOS);
|
||||
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
AMDRGPControl *DummyDriver::GetRGPControl()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t DummyDriver::MakeOutputWindow(WindowingData window, bool depth)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void DummyDriver::DestroyOutputWindow(uint64_t id)
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::CheckResizeOutputWindow(uint64_t id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DummyDriver::SetOutputWindowDimensions(uint64_t id, int32_t w, int32_t h)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::GetOutputWindowData(uint64_t id, bytebuf &retData)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::ClearOutputWindowColor(uint64_t id, FloatVector col)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::BindOutputWindow(uint64_t id, bool depth)
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::IsOutputWindowVisible(uint64_t id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DummyDriver::FlipOutputWindow(uint64_t id)
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast,
|
||||
float *minval, float *maxval)
|
||||
{
|
||||
*minval = 0.0f;
|
||||
*maxval = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DummyDriver::GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast,
|
||||
float minval, float maxval, const rdcfixedarray<bool, 4> &channels,
|
||||
rdcarray<uint32_t> &histogram)
|
||||
{
|
||||
histogram.fill(256, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
void DummyDriver::PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub,
|
||||
CompType typeCast, float pixel[4])
|
||||
{
|
||||
}
|
||||
|
||||
ResourceId DummyDriver::CreateProxyTexture(const TextureDescription &templateTex)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
void DummyDriver::SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data,
|
||||
size_t dataSize)
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::IsTextureSupported(const TextureDescription &tex)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ResourceId DummyDriver::CreateProxyBuffer(const BufferDescription &templateBuf)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
void DummyDriver::SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondaryDraws,
|
||||
const MeshDisplay &cfg)
|
||||
{
|
||||
}
|
||||
|
||||
bool DummyDriver::RenderTexture(TextureDisplay cfg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DummyDriver::SetCustomShaderIncludes(const rdcarray<rdcstr> &directories)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf &source,
|
||||
const rdcstr &entry, const ShaderCompileFlags &compileFlags,
|
||||
ShaderStage type, ResourceId &id, rdcstr &errors)
|
||||
{
|
||||
id = ResourceId();
|
||||
errors = "Unrecoverable error encountered while analysing capture";
|
||||
}
|
||||
|
||||
rdcarray<ShaderEncoding> DummyDriver::GetCustomShaderEncodings()
|
||||
{
|
||||
return {ShaderEncoding::HLSL, ShaderEncoding::GLSL};
|
||||
}
|
||||
|
||||
ResourceId DummyDriver::ApplyCustomShader(ResourceId shader, ResourceId texid,
|
||||
const Subresource &sub, CompType typeCast)
|
||||
{
|
||||
return ResourceId();
|
||||
}
|
||||
|
||||
void DummyDriver::FreeCustomShader(ResourceId id)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::RenderCheckerboard(FloatVector dark, FloatVector light)
|
||||
{
|
||||
}
|
||||
|
||||
void DummyDriver::RenderHighlightBox(float w, float h, float scale)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t DummyDriver::PickVertex(uint32_t eventId, int32_t width, int32_t height,
|
||||
const MeshDisplay &cfg, uint32_t x, uint32_t y)
|
||||
{
|
||||
return ~0U;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "replay_driver.h"
|
||||
|
||||
// this is a dummy driver that can be swapped to if the underlying replay/remote driver encounters
|
||||
// some fatal problem and shouldn't be used further. It saves significantly on needing to
|
||||
// bullet-proof each driver since instead we just need to make error paths clear and short, and rely
|
||||
// on the replay controller to detect errors and swap to a dummy driver immediately
|
||||
class DummyDriver : public IReplayDriver
|
||||
{
|
||||
public:
|
||||
DummyDriver(IReplayDriver *original, const rdcarray<ShaderReflection *> &shaders);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
APIProperties GetAPIProperties();
|
||||
|
||||
rdcarray<ResourceDescription> GetResources();
|
||||
|
||||
rdcarray<BufferDescription> GetBuffers();
|
||||
BufferDescription GetBuffer(ResourceId id);
|
||||
|
||||
rdcarray<TextureDescription> GetTextures();
|
||||
TextureDescription GetTexture(ResourceId id);
|
||||
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
|
||||
rdcarray<ShaderEntryPoint> GetShaderEntryPoints(ResourceId shader);
|
||||
ShaderReflection *GetShader(ResourceId pipeline, ResourceId shader, ShaderEntryPoint entry);
|
||||
|
||||
rdcarray<rdcstr> GetDisassemblyTargets(bool withPipeline);
|
||||
rdcstr DisassembleShader(ResourceId pipeline, const ShaderReflection *refl, const rdcstr &target);
|
||||
|
||||
rdcarray<EventUsage> GetUsage(ResourceId id);
|
||||
|
||||
void SetPipelineStates(D3D11Pipe::State *d3d11, D3D12Pipe::State *d3d12, GLPipe::State *gl,
|
||||
VKPipe::State *vk);
|
||||
void SavePipelineState(uint32_t eventId);
|
||||
|
||||
FrameRecord GetFrameRecord();
|
||||
|
||||
ReplayStatus ReadLogInitialisation(RDCFile *rdc, bool storeStructuredBuffers);
|
||||
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
|
||||
SDFile *GetStructuredFile();
|
||||
|
||||
rdcarray<uint32_t> GetPassEvents(uint32_t eventId);
|
||||
|
||||
void InitPostVSBuffers(uint32_t eventId);
|
||||
void InitPostVSBuffers(const rdcarray<uint32_t> &passEvents);
|
||||
|
||||
ResourceId GetLiveID(ResourceId id);
|
||||
|
||||
MeshFormat GetPostVSBuffers(uint32_t eventId, uint32_t instID, uint32_t viewID,
|
||||
MeshDataStage stage);
|
||||
|
||||
void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, bytebuf &retData);
|
||||
void GetTextureData(ResourceId tex, const Subresource &sub, const GetTextureDataParams ¶ms,
|
||||
bytebuf &data);
|
||||
|
||||
void BuildTargetShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry,
|
||||
const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id,
|
||||
rdcstr &errors);
|
||||
rdcarray<ShaderEncoding> GetTargetShaderEncodings();
|
||||
void ReplaceResource(ResourceId from, ResourceId to);
|
||||
void RemoveReplacement(ResourceId id);
|
||||
void FreeTargetResource(ResourceId id);
|
||||
|
||||
rdcarray<GPUCounter> EnumerateCounters();
|
||||
CounterDescription DescribeCounter(GPUCounter counterID);
|
||||
rdcarray<CounterResult> FetchCounters(const rdcarray<GPUCounter> &counterID);
|
||||
|
||||
void FillCBufferVariables(ResourceId pipeline, ResourceId shader, rdcstr entryPoint,
|
||||
uint32_t cbufSlot, rdcarray<ShaderVariable> &outvars,
|
||||
const bytebuf &data);
|
||||
|
||||
rdcarray<PixelModification> PixelHistory(rdcarray<EventUsage> events, ResourceId target, uint32_t x,
|
||||
uint32_t y, const Subresource &sub, CompType typeCast);
|
||||
ShaderDebugTrace *DebugVertex(uint32_t eventId, uint32_t vertid, uint32_t instid, uint32_t idx,
|
||||
uint32_t view);
|
||||
ShaderDebugTrace *DebugPixel(uint32_t eventId, uint32_t x, uint32_t y, uint32_t sample,
|
||||
uint32_t primitive);
|
||||
ShaderDebugTrace *DebugThread(uint32_t eventId, const rdcfixedarray<uint32_t, 3> &groupid,
|
||||
const rdcfixedarray<uint32_t, 3> &threadid);
|
||||
rdcarray<ShaderDebugState> ContinueDebug(ShaderDebugger *debugger);
|
||||
void FreeDebugger(ShaderDebugger *debugger);
|
||||
|
||||
ResourceId RenderOverlay(ResourceId texid, FloatVector clearCol, DebugOverlay overlay,
|
||||
uint32_t eventId, const rdcarray<uint32_t> &passEvents);
|
||||
|
||||
bool IsRenderOutput(ResourceId id);
|
||||
|
||||
void FileChanged();
|
||||
|
||||
bool NeedRemapForFetch(const ResourceFormat &format);
|
||||
|
||||
DriverInformation GetDriverInfo();
|
||||
|
||||
rdcarray<GPUDevice> GetAvailableGPUs();
|
||||
|
||||
// IReplayDriver
|
||||
bool IsRemoteProxy();
|
||||
|
||||
ReplayStatus FatalErrorCheck();
|
||||
IReplayDriver *MakeDummyDriver();
|
||||
|
||||
rdcarray<WindowingSystem> GetSupportedWindowSystems();
|
||||
|
||||
AMDRGPControl *GetRGPControl();
|
||||
|
||||
uint64_t MakeOutputWindow(WindowingData window, bool depth);
|
||||
void DestroyOutputWindow(uint64_t id);
|
||||
bool CheckResizeOutputWindow(uint64_t id);
|
||||
void SetOutputWindowDimensions(uint64_t id, int32_t w, int32_t h);
|
||||
void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h);
|
||||
void GetOutputWindowData(uint64_t id, bytebuf &retData);
|
||||
void ClearOutputWindowColor(uint64_t id, FloatVector col);
|
||||
void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil);
|
||||
void BindOutputWindow(uint64_t id, bool depth);
|
||||
bool IsOutputWindowVisible(uint64_t id);
|
||||
void FlipOutputWindow(uint64_t id);
|
||||
|
||||
bool GetMinMax(ResourceId texid, const Subresource &sub, CompType typeCast, float *minval,
|
||||
float *maxval);
|
||||
bool GetHistogram(ResourceId texid, const Subresource &sub, CompType typeCast, float minval,
|
||||
float maxval, const rdcfixedarray<bool, 4> &channels,
|
||||
rdcarray<uint32_t> &histogram);
|
||||
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, const Subresource &sub,
|
||||
CompType typeCast, float pixel[4]);
|
||||
|
||||
ResourceId CreateProxyTexture(const TextureDescription &templateTex);
|
||||
void SetProxyTextureData(ResourceId texid, const Subresource &sub, byte *data, size_t dataSize);
|
||||
bool IsTextureSupported(const TextureDescription &tex);
|
||||
|
||||
ResourceId CreateProxyBuffer(const BufferDescription &templateBuf);
|
||||
void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize);
|
||||
|
||||
void RenderMesh(uint32_t eventId, const rdcarray<MeshFormat> &secondaryDraws,
|
||||
const MeshDisplay &cfg);
|
||||
bool RenderTexture(TextureDisplay cfg);
|
||||
|
||||
void SetCustomShaderIncludes(const rdcarray<rdcstr> &directories);
|
||||
void BuildCustomShader(ShaderEncoding sourceEncoding, const bytebuf &source, const rdcstr &entry,
|
||||
const ShaderCompileFlags &compileFlags, ShaderStage type, ResourceId &id,
|
||||
rdcstr &errors);
|
||||
rdcarray<ShaderEncoding> GetCustomShaderEncodings();
|
||||
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, const Subresource &sub,
|
||||
CompType typeCast);
|
||||
void FreeCustomShader(ResourceId id);
|
||||
|
||||
void RenderCheckerboard(FloatVector dark, FloatVector light);
|
||||
|
||||
void RenderHighlightBox(float w, float h, float scale);
|
||||
|
||||
uint32_t PickVertex(uint32_t eventId, int32_t width, int32_t height, const MeshDisplay &cfg,
|
||||
uint32_t x, uint32_t y);
|
||||
|
||||
private:
|
||||
virtual ~DummyDriver();
|
||||
|
||||
rdcarray<ShaderReflection *> m_Shaders;
|
||||
SDFile *m_SDFile;
|
||||
|
||||
APIProperties m_Props;
|
||||
rdcarray<ResourceDescription> m_Resources;
|
||||
rdcarray<BufferDescription> m_Buffers;
|
||||
rdcarray<TextureDescription> m_Textures;
|
||||
FrameRecord m_FrameRecord;
|
||||
rdcarray<ShaderEncoding> m_TargetEncodings;
|
||||
DriverInformation m_DriverInfo;
|
||||
|
||||
bool m_Proxy;
|
||||
rdcarray<GPUDevice> m_GPUs;
|
||||
rdcarray<WindowingSystem> m_WindowSystems;
|
||||
rdcarray<ShaderEncoding> m_CustomEncodings;
|
||||
};
|
||||
@@ -77,11 +77,13 @@ void ReplayController::SetFrameEvent(uint32_t eventId, bool force)
|
||||
m_EventID = eventId;
|
||||
|
||||
m_pDevice->ReplayLog(eventId, eReplay_WithoutDraw);
|
||||
FatalErrorCheck();
|
||||
|
||||
for(size_t i = 0; i < m_Outputs.size(); i++)
|
||||
m_Outputs[i]->SetFrameEvent(eventId);
|
||||
|
||||
m_pDevice->ReplayLog(eventId, eReplay_OnlyDraw);
|
||||
FatalErrorCheck();
|
||||
|
||||
FetchPipelineState(eventId);
|
||||
}
|
||||
@@ -154,7 +156,9 @@ rdcstr ReplayController::DisassembleShader(ResourceId pipeline, const ShaderRefl
|
||||
if(t == target)
|
||||
return GCNISA::Disassemble(refl->encoding, refl->stage, refl->rawBytes, target);
|
||||
|
||||
return m_pDevice->DisassembleShader(m_pDevice->GetLiveID(pipeline), refl, target);
|
||||
rdcstr ret = m_pDevice->DisassembleShader(m_pDevice->GetLiveID(pipeline), refl, target);
|
||||
FatalErrorCheck();
|
||||
return ret;
|
||||
}
|
||||
|
||||
FrameDescription ReplayController::GetFrameInfo()
|
||||
@@ -414,7 +418,9 @@ rdcarray<CounterResult> ReplayController::FetchCounters(const rdcarray<GPUCounte
|
||||
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
return m_pDevice->FetchCounters(counters);
|
||||
rdcarray<CounterResult> ret = m_pDevice->FetchCounters(counters);
|
||||
FatalErrorCheck();
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcarray<GPUCounter> ReplayController::EnumerateCounters()
|
||||
@@ -490,17 +496,18 @@ MeshFormat ReplayController::GetPostVSData(uint32_t instID, uint32_t viewID, Mes
|
||||
|
||||
ActionDescription *action = GetActionByEID(m_EventID);
|
||||
|
||||
MeshFormat ret;
|
||||
RDCEraseEl(ret);
|
||||
|
||||
if(action == NULL || !(action->flags & ActionFlags::Drawcall))
|
||||
return MeshFormat();
|
||||
|
||||
instID = RDCMIN(instID, action->numInstances - 1);
|
||||
|
||||
m_pDevice->InitPostVSBuffers(action->eventId);
|
||||
FatalErrorCheck();
|
||||
|
||||
return m_pDevice->GetPostVSBuffers(action->eventId, instID, viewID, stage);
|
||||
MeshFormat ret = m_pDevice->GetPostVSBuffers(action->eventId, instID, viewID, stage);
|
||||
FatalErrorCheck();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bytebuf ReplayController::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len)
|
||||
@@ -521,6 +528,7 @@ bytebuf ReplayController::GetBufferData(ResourceId buff, uint64_t offset, uint64
|
||||
}
|
||||
|
||||
m_pDevice->GetBufferData(liveId, offset, len, retData);
|
||||
FatalErrorCheck();
|
||||
|
||||
return retData;
|
||||
}
|
||||
@@ -541,6 +549,7 @@ bytebuf ReplayController::GetTextureData(ResourceId tex, const Subresource &sub)
|
||||
}
|
||||
|
||||
m_pDevice->GetTextureData(liveId, sub, GetTextureDataParams(), ret);
|
||||
FatalErrorCheck();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -856,6 +865,7 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const rdcstr &pa
|
||||
|
||||
bytebuf data;
|
||||
m_pDevice->GetTextureData(liveid, sub, params, data);
|
||||
FatalErrorCheck();
|
||||
|
||||
if(data.empty())
|
||||
{
|
||||
@@ -1530,6 +1540,7 @@ rdcarray<PixelModification> ReplayController::PixelHistory(ResourceId target, ui
|
||||
return ret;
|
||||
|
||||
ret = m_pDevice->PixelHistory(events, id, x, y, subresource, typeCast);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
@@ -1550,6 +1561,7 @@ PixelValue ReplayController::PickPixel(ResourceId tex, uint32_t x, uint32_t y,
|
||||
return ret;
|
||||
|
||||
m_pDevice->PickPixel(m_pDevice->GetLiveID(tex), x, y, sub, typeCast, ret.floatValue.data());
|
||||
FatalErrorCheck();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1564,6 +1576,7 @@ rdcpair<PixelValue, PixelValue> ReplayController::GetMinMax(ResourceId textureId
|
||||
|
||||
m_pDevice->GetMinMax(m_pDevice->GetLiveID(textureId), sub, typeCast, &minval.floatValue[0],
|
||||
&maxval.floatValue[0]);
|
||||
FatalErrorCheck();
|
||||
|
||||
return make_rdcpair(minval, maxval);
|
||||
}
|
||||
@@ -1578,6 +1591,7 @@ rdcarray<uint32_t> ReplayController::GetHistogram(ResourceId textureId, const Su
|
||||
|
||||
m_pDevice->GetHistogram(m_pDevice->GetLiveID(textureId), sub, typeCast, minval, maxval, channels,
|
||||
hist);
|
||||
FatalErrorCheck();
|
||||
|
||||
return hist;
|
||||
}
|
||||
@@ -1590,9 +1604,13 @@ ShaderDebugTrace *ReplayController::DebugVertex(uint32_t vertid, uint32_t instid
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ShaderDebugTrace *ret = m_pDevice->DebugVertex(m_EventID, vertid, instid, idx, view);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
if(ret->debugger)
|
||||
m_Debuggers.push_back(ret->debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1604,9 +1622,13 @@ ShaderDebugTrace *ReplayController::DebugPixel(uint32_t x, uint32_t y, uint32_t
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ShaderDebugTrace *ret = m_pDevice->DebugPixel(m_EventID, x, y, sample, primitive);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
if(ret->debugger)
|
||||
m_Debuggers.push_back(ret->debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1618,9 +1640,13 @@ ShaderDebugTrace *ReplayController::DebugThread(const rdcfixedarray<uint32_t, 3>
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ShaderDebugTrace *ret = m_pDevice->DebugThread(m_EventID, groupid, threadid);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
if(ret->debugger)
|
||||
m_Debuggers.push_back(ret->debugger);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1631,6 +1657,7 @@ rdcarray<ShaderDebugState> ReplayController::ContinueDebug(ShaderDebugger *debug
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
rdcarray<ShaderDebugState> ret = m_pDevice->ContinueDebug(debugger);
|
||||
FatalErrorCheck();
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1641,6 +1668,7 @@ void ReplayController::FreeTrace(ShaderDebugTrace *trace)
|
||||
|
||||
if(trace)
|
||||
{
|
||||
m_Debuggers.removeOne(trace->debugger);
|
||||
m_pDevice->FreeDebugger(trace->debugger);
|
||||
delete trace;
|
||||
}
|
||||
@@ -1659,7 +1687,10 @@ rdcarray<ShaderVariable> ReplayController::GetCBufferVariableContents(
|
||||
{
|
||||
buffer = m_pDevice->GetLiveID(buffer);
|
||||
if(buffer != ResourceId())
|
||||
{
|
||||
m_pDevice->GetBufferData(buffer, offset, length, data);
|
||||
FatalErrorCheck();
|
||||
}
|
||||
}
|
||||
|
||||
rdcarray<ShaderVariable> v;
|
||||
@@ -1668,7 +1699,10 @@ rdcarray<ShaderVariable> ReplayController::GetCBufferVariableContents(
|
||||
shader = m_pDevice->GetLiveID(shader);
|
||||
|
||||
if(shader != ResourceId())
|
||||
{
|
||||
m_pDevice->FillCBufferVariables(pipeline, shader, entryPoint, cbufslot, v, data);
|
||||
FatalErrorCheck();
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -1705,6 +1739,8 @@ rdcstr ReplayController::CreateRGPProfile(WindowingData window)
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
m_pDevice->ReplayLog(10000000, eReplay_Full);
|
||||
if(FatalErrorCheck())
|
||||
return "";
|
||||
output->Display();
|
||||
}
|
||||
|
||||
@@ -1730,12 +1766,16 @@ rdcstr ReplayController::CreateRGPProfile(WindowingData window)
|
||||
|
||||
output->Display();
|
||||
m_pDevice->ReplayLog(10000000, eReplay_Full);
|
||||
if(FatalErrorCheck())
|
||||
return "";
|
||||
}
|
||||
|
||||
output->Display();
|
||||
|
||||
// restore back to where we were
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_Full);
|
||||
if(FatalErrorCheck())
|
||||
return "";
|
||||
|
||||
ShutdownOutput(output);
|
||||
|
||||
@@ -1783,12 +1823,14 @@ void ReplayController::ReplayLoop(WindowingData window, ResourceId texid)
|
||||
while(Atomic::CmpExch32(&m_ReplayLoopCancel, 0, 0) == 0)
|
||||
{
|
||||
m_pDevice->ReplayLog(10000000, eReplay_Full);
|
||||
FatalErrorCheck();
|
||||
|
||||
output->Display();
|
||||
}
|
||||
|
||||
// restore back to where we were
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_Full);
|
||||
FatalErrorCheck();
|
||||
|
||||
ShutdownOutput(output);
|
||||
|
||||
@@ -1865,6 +1907,48 @@ void ReplayController::Shutdown()
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool ReplayController::FatalErrorCheck()
|
||||
{
|
||||
// we've already processed the fatal error if we have a status
|
||||
if(m_FatalError != ReplayStatus::Succeeded)
|
||||
return false;
|
||||
|
||||
m_FatalError = m_pDevice->FatalErrorCheck();
|
||||
|
||||
if(m_FatalError != ReplayStatus::Succeeded)
|
||||
{
|
||||
RDCLOG("Fatal error detected: %s", ToStr(m_FatalError).c_str());
|
||||
|
||||
IReplayDriver *old = m_pDevice;
|
||||
|
||||
// replace our driver with a dummy
|
||||
m_pDevice = m_pDevice->MakeDummyDriver();
|
||||
|
||||
// replace the outputs as well
|
||||
for(size_t i = 0; i < m_Outputs.size(); i++)
|
||||
{
|
||||
old->DestroyOutputWindow(m_Outputs[i]->m_MainOutput.outputID);
|
||||
old->DestroyOutputWindow(m_Outputs[i]->m_PixelContext.outputID);
|
||||
m_Outputs[i]->ClearThumbnails();
|
||||
|
||||
m_Outputs[i]->m_pDevice = m_pDevice;
|
||||
}
|
||||
|
||||
// delete the old replay
|
||||
old->Shutdown();
|
||||
|
||||
// reset pipeline states to default
|
||||
m_D3D11PipelineState = D3D11Pipe::State();
|
||||
m_D3D12PipelineState = D3D12Pipe::State();
|
||||
m_GLPipelineState = GLPipe::State();
|
||||
m_VulkanPipelineState = VKPipe::State();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rdcarray<ShaderEncoding> ReplayController::GetCustomShaderEncodings()
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
@@ -1912,6 +1996,7 @@ rdcpair<ResourceId, rdcstr> ReplayController::BuildTargetShader(
|
||||
}
|
||||
|
||||
m_pDevice->BuildTargetShader(sourceEncoding, source, entry, compileFlags, type, id, errs);
|
||||
FatalErrorCheck();
|
||||
|
||||
if(id != ResourceId())
|
||||
m_TargetResources.insert(id);
|
||||
@@ -1952,6 +2037,7 @@ rdcpair<ResourceId, rdcstr> ReplayController::BuildCustomShader(
|
||||
RDCLOG("Building custom shader");
|
||||
|
||||
m_pDevice->BuildCustomShader(sourceEncoding, source, entry, compileFlags, type, id, errs);
|
||||
FatalErrorCheck();
|
||||
|
||||
if(id != ResourceId())
|
||||
{
|
||||
@@ -1987,6 +2073,7 @@ void ReplayController::ReplaceResource(ResourceId from, ResourceId to)
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
m_pDevice->ReplaceResource(from, to);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
@@ -2000,6 +2087,7 @@ void ReplayController::RemoveReplacement(ResourceId id)
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
m_pDevice->RemoveReplacement(id);
|
||||
FatalErrorCheck();
|
||||
|
||||
SetFrameEvent(m_EventID, true);
|
||||
|
||||
@@ -2054,6 +2142,7 @@ ReplayStatus ReplayController::PostCreateInit(IReplayDriver *device, RDCFile *rd
|
||||
GCNISA::CacheSupport(m_APIProps.pipelineType);
|
||||
|
||||
ReplayStatus status = m_pDevice->ReadLogInitialisation(rdc, false);
|
||||
FatalErrorCheck();
|
||||
|
||||
m_pDevice->SetPipelineStates(&m_D3D11PipelineState, &m_D3D12PipelineState, &m_GLPipelineState,
|
||||
&m_VulkanPipelineState);
|
||||
@@ -2101,6 +2190,7 @@ void ReplayController::FetchPipelineState(uint32_t eventId)
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
m_pDevice->SavePipelineState(eventId);
|
||||
FatalErrorCheck();
|
||||
|
||||
if(m_APIProps.pipelineType == GraphicsAPI::D3D11)
|
||||
m_PipeState.SetState(&m_D3D11PipelineState);
|
||||
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
|
||||
uint64_t m_ThreadID;
|
||||
|
||||
ReplayController *m_pRenderer;
|
||||
ReplayController *m_pController;
|
||||
|
||||
bool m_OverlayDirty;
|
||||
bool m_ForceOverlayRefresh;
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
const rdcarray<BufferDescription> &GetBuffers();
|
||||
const rdcarray<ResourceDescription> &GetResources();
|
||||
rdcarray<DebugMessage> GetDebugMessages();
|
||||
|
||||
ReplayStatus GetFatalErrorStatus() { return m_FatalError; }
|
||||
rdcarray<ShaderEntryPoint> GetShaderEntryPoints(ResourceId shader);
|
||||
const ShaderReflection *GetShader(ResourceId pipeline, ResourceId shader, ShaderEntryPoint entry);
|
||||
|
||||
@@ -218,6 +218,8 @@ public:
|
||||
void ShutdownOutput(IReplayOutput *output);
|
||||
void Shutdown();
|
||||
|
||||
bool FatalErrorCheck();
|
||||
|
||||
private:
|
||||
virtual ~ReplayController();
|
||||
ReplayStatus PostCreateInit(IReplayDriver *device, RDCFile *rdc);
|
||||
@@ -240,6 +242,8 @@ private:
|
||||
int32_t m_ReplayLoopCancel = 0;
|
||||
int32_t m_ReplayLoopFinished = 0;
|
||||
|
||||
ReplayStatus m_FatalError = ReplayStatus::Succeeded;
|
||||
|
||||
uint32_t m_EventID;
|
||||
|
||||
std::map<uint32_t, uint32_t> m_EventRemap;
|
||||
@@ -258,6 +262,8 @@ private:
|
||||
|
||||
IReplayDriver *m_pDevice;
|
||||
|
||||
rdcarray<ShaderDebugger *> m_Debuggers;
|
||||
|
||||
std::set<ResourceId> m_TargetResources;
|
||||
std::set<ResourceId> m_CustomShaders;
|
||||
|
||||
|
||||
@@ -212,6 +212,7 @@ public:
|
||||
virtual bool IsRenderOutput(ResourceId id) = 0;
|
||||
|
||||
virtual void FileChanged() = 0;
|
||||
virtual ReplayStatus FatalErrorCheck() = 0;
|
||||
|
||||
virtual bool NeedRemapForFetch(const ResourceFormat &format) = 0;
|
||||
|
||||
@@ -225,6 +226,8 @@ class IReplayDriver : public IRemoteDriver
|
||||
public:
|
||||
virtual bool IsRemoteProxy() = 0;
|
||||
|
||||
virtual IReplayDriver *MakeDummyDriver() = 0;
|
||||
|
||||
virtual rdcarray<WindowingSystem> GetSupportedWindowSystems() = 0;
|
||||
|
||||
virtual AMDRGPControl *GetRGPControl() = 0;
|
||||
|
||||
@@ -88,7 +88,7 @@ ReplayOutput::ReplayOutput(ReplayController *parent, WindowingData window, Repla
|
||||
{
|
||||
m_ThreadID = Threading::GetCurrentID();
|
||||
|
||||
m_pRenderer = parent;
|
||||
m_pController = parent;
|
||||
|
||||
m_MainOutput.dirty = true;
|
||||
|
||||
@@ -118,6 +118,8 @@ ReplayOutput::ReplayOutput(ReplayController *parent, WindowingData window, Repla
|
||||
m_MainOutput.outputID = 0;
|
||||
m_MainOutput.texture = ResourceId();
|
||||
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->GetOutputWindowDimensions(m_MainOutput.outputID, m_Width, m_Height);
|
||||
|
||||
m_CustomShaderResourceId = ResourceId();
|
||||
@@ -130,11 +132,11 @@ ReplayOutput::~ReplayOutput()
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
m_CustomShaderResourceId = ResourceId();
|
||||
|
||||
m_pDevice->DestroyOutputWindow(m_MainOutput.outputID);
|
||||
m_pDevice->DestroyOutputWindow(m_PixelContext.outputID);
|
||||
|
||||
m_CustomShaderResourceId = ResourceId();
|
||||
|
||||
ClearThumbnails();
|
||||
}
|
||||
|
||||
@@ -142,7 +144,7 @@ void ReplayOutput::Shutdown()
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
m_pRenderer->ShutdownOutput(this);
|
||||
m_pController->ShutdownOutput(this);
|
||||
}
|
||||
|
||||
void ReplayOutput::SetDimensions(int32_t width, int32_t height)
|
||||
@@ -152,6 +154,7 @@ void ReplayOutput::SetDimensions(int32_t width, int32_t height)
|
||||
m_pDevice->SetOutputWindowDimensions(m_MainOutput.outputID, width > 0 ? width : 1,
|
||||
height > 0 ? height : 1);
|
||||
m_pDevice->GetOutputWindowDimensions(m_MainOutput.outputID, m_Width, m_Height);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
bytebuf ReplayOutput::ReadbackOutputTexture()
|
||||
@@ -160,6 +163,7 @@ bytebuf ReplayOutput::ReadbackOutputTexture()
|
||||
|
||||
bytebuf data;
|
||||
m_pDevice->GetOutputWindowData(m_MainOutput.outputID, data);
|
||||
m_pController->FatalErrorCheck();
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -226,7 +230,7 @@ void ReplayOutput::RefreshOverlay()
|
||||
{
|
||||
CHECK_REPLAY_THREAD();
|
||||
|
||||
ActionDescription *action = m_pRenderer->GetActionByEID(m_EventID);
|
||||
ActionDescription *action = m_pController->GetActionByEID(m_EventID);
|
||||
|
||||
passEvents = m_pDevice->GetPassEvents(m_EventID);
|
||||
|
||||
@@ -254,12 +258,15 @@ void ReplayOutput::RefreshOverlay()
|
||||
if(action != NULL && (action->flags & ActionFlags::Drawcall))
|
||||
{
|
||||
m_pDevice->InitPostVSBuffers(action->eventId);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(postVSWholePass && !passEvents.empty())
|
||||
{
|
||||
m_pDevice->InitPostVSBuffers(passEvents);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,6 +281,7 @@ void ReplayOutput::RefreshOverlay()
|
||||
|
||||
m_OverlayResourceId =
|
||||
m_pDevice->RenderOverlay(id, f, m_RenderData.texDisplay.overlay, m_EventID, passEvents);
|
||||
m_pController->FatalErrorCheck();
|
||||
m_OverlayDirty = false;
|
||||
}
|
||||
else
|
||||
@@ -301,8 +309,10 @@ ResourceId ReplayOutput::GetDebugOverlayTexID()
|
||||
if(m_OverlayDirty)
|
||||
{
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
RefreshOverlay();
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_OnlyDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
return m_OverlayResourceId;
|
||||
@@ -326,6 +336,8 @@ bool ReplayOutput::SetPixelContext(WindowingData window)
|
||||
m_PixelContext.texture = ResourceId();
|
||||
m_PixelContext.depthMode = false;
|
||||
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
RDCASSERT(m_PixelContext.outputID > 0);
|
||||
|
||||
return m_PixelContext.outputID != 0;
|
||||
@@ -342,12 +354,12 @@ bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, const Su
|
||||
|
||||
bool depthMode = false;
|
||||
|
||||
for(size_t t = 0; t < m_pRenderer->m_Textures.size(); t++)
|
||||
for(size_t t = 0; t < m_pController->m_Textures.size(); t++)
|
||||
{
|
||||
if(m_pRenderer->m_Textures[t].resourceId == texID)
|
||||
if(m_pController->m_Textures[t].resourceId == texID)
|
||||
{
|
||||
depthMode = (m_pRenderer->m_Textures[t].creationFlags & TextureCategory::DepthTarget) ||
|
||||
(m_pRenderer->m_Textures[t].format.compType == CompType::Depth);
|
||||
depthMode = (m_pController->m_Textures[t].creationFlags & TextureCategory::DepthTarget) ||
|
||||
(m_pController->m_Textures[t].format.compType == CompType::Depth);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -374,6 +386,8 @@ bool ReplayOutput::AddThumbnail(WindowingData window, ResourceId texID, const Su
|
||||
p.typeCast = typeCast;
|
||||
p.dirty = true;
|
||||
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
RDCASSERT(p.outputID > 0);
|
||||
|
||||
m_Thumbnails.push_back(p);
|
||||
@@ -387,7 +401,7 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ActionDescription *action = m_pRenderer->GetActionByEID(m_EventID);
|
||||
ActionDescription *action = m_pController->GetActionByEID(m_EventID);
|
||||
|
||||
const rdcpair<uint32_t, uint32_t> errorReturn = {~0U, ~0U};
|
||||
|
||||
@@ -432,6 +446,9 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
MeshFormat fmt =
|
||||
m_pDevice->GetPostVSBuffers(action->eventId, m_RenderData.meshDisplay.curInstance,
|
||||
m_RenderData.meshDisplay.curView, m_RenderData.meshDisplay.type);
|
||||
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
uint64_t elemOffset = cfg.position.vertexByteOffset - fmt.vertexByteOffset;
|
||||
|
||||
for(uint32_t inst = firstInst; inst < maxInst; inst++)
|
||||
@@ -439,10 +456,14 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
// find the start of this buffer, and apply the element offset, then pick in that instance
|
||||
fmt = m_pDevice->GetPostVSBuffers(action->eventId, inst, m_RenderData.meshDisplay.curView,
|
||||
m_RenderData.meshDisplay.type);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(fmt.vertexResourceId != ResourceId())
|
||||
cfg.position.vertexByteOffset = fmt.vertexByteOffset + elemOffset;
|
||||
|
||||
uint32_t vert = m_pDevice->PickVertex(m_EventID, m_Width, m_Height, cfg, x, y);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(vert != ~0U)
|
||||
{
|
||||
return make_rdcpair(vert, inst);
|
||||
@@ -454,6 +475,7 @@ rdcpair<uint32_t, uint32_t> ReplayOutput::PickVertex(uint32_t x, uint32_t y)
|
||||
else
|
||||
{
|
||||
uint32_t vert = m_pDevice->PickVertex(m_EventID, m_Width, m_Height, cfg, x, y);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
if(vert != ~0U)
|
||||
return make_rdcpair(vert, m_RenderData.meshDisplay.curInstance);
|
||||
@@ -492,6 +514,8 @@ void ReplayOutput::ClearBackground(uint64_t outputID, const FloatVector &backgro
|
||||
RenderDoc::Inst().LightCheckerboardColor());
|
||||
else
|
||||
m_pDevice->ClearOutputWindowColor(outputID, ConvertSRGBToLinear(backgroundColor));
|
||||
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
void ReplayOutput::DisplayContext()
|
||||
@@ -500,13 +524,17 @@ void ReplayOutput::DisplayContext()
|
||||
|
||||
if(m_PixelContext.outputID == 0)
|
||||
return;
|
||||
|
||||
m_pDevice->BindOutputWindow(m_PixelContext.outputID, false);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
ClearBackground(m_PixelContext.outputID, m_RenderData.texDisplay.backgroundColor);
|
||||
|
||||
if((m_Type != ReplayOutputType::Texture) || (m_ContextX < 0.0f && m_ContextY < 0.0f) ||
|
||||
(m_RenderData.texDisplay.resourceId == ResourceId()))
|
||||
{
|
||||
m_pDevice->FlipOutputWindow(m_PixelContext.outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -552,10 +580,13 @@ void ReplayOutput::DisplayContext()
|
||||
disp.resourceId = m_pDevice->GetLiveID(disp.resourceId);
|
||||
|
||||
m_pDevice->RenderTexture(disp);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->RenderHighlightBox(w, h, contextZoom);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->FlipOutputWindow(m_PixelContext.outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
void ReplayOutput::Display()
|
||||
@@ -589,6 +620,7 @@ void ReplayOutput::Display()
|
||||
}
|
||||
|
||||
m_pDevice->FlipOutputWindow(m_MainOutput.outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
DisplayContext();
|
||||
}
|
||||
@@ -596,8 +628,10 @@ void ReplayOutput::Display()
|
||||
{
|
||||
m_pDevice->BindOutputWindow(m_MainOutput.outputID, false);
|
||||
m_pDevice->FlipOutputWindow(m_MainOutput.outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
m_pDevice->BindOutputWindow(m_PixelContext.outputID, false);
|
||||
m_pDevice->FlipOutputWindow(m_PixelContext.outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_Thumbnails.size(); i++)
|
||||
@@ -632,8 +666,10 @@ void ReplayOutput::Display()
|
||||
light2.z = light.z;
|
||||
light2.w = 1.0f;
|
||||
m_pDevice->RenderCheckerboard(dark2, light2);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->FlipOutputWindow(m_Thumbnails[i].outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -667,8 +703,10 @@ void ReplayOutput::Display()
|
||||
disp.green = disp.blue = false;
|
||||
|
||||
m_pDevice->RenderTexture(disp);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->FlipOutputWindow(m_Thumbnails[i].outputID);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_Thumbnails[i].dirty = false;
|
||||
}
|
||||
@@ -680,7 +718,7 @@ void ReplayOutput::DisplayTex()
|
||||
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ActionDescription *action = m_pRenderer->GetActionByEID(m_EventID);
|
||||
ActionDescription *action = m_pController->GetActionByEID(m_EventID);
|
||||
|
||||
if(m_MainOutput.outputID == 0)
|
||||
return;
|
||||
@@ -701,14 +739,17 @@ void ReplayOutput::DisplayTex()
|
||||
if(m_OverlayDirty)
|
||||
{
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
RefreshOverlay();
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_OnlyDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
}
|
||||
else if(m_ForceOverlayRefresh)
|
||||
{
|
||||
m_ForceOverlayRefresh = false;
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_Full);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
if(m_RenderData.texDisplay.customShaderId != ResourceId())
|
||||
@@ -716,6 +757,7 @@ void ReplayOutput::DisplayTex()
|
||||
m_CustomShaderResourceId =
|
||||
m_pDevice->ApplyCustomShader(m_RenderData.texDisplay.customShaderId, texDisplay.resourceId,
|
||||
texDisplay.subresource, texDisplay.typeCast);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
texDisplay.resourceId = m_pDevice->GetLiveID(m_CustomShaderResourceId);
|
||||
texDisplay.typeCast = CompType::Typeless;
|
||||
@@ -739,6 +781,7 @@ void ReplayOutput::DisplayTex()
|
||||
}
|
||||
|
||||
m_pDevice->RenderTexture(texDisplay);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
ResourceId id = m_pDevice->GetLiveID(m_RenderData.texDisplay.resourceId);
|
||||
|
||||
@@ -760,6 +803,7 @@ void ReplayOutput::DisplayTex()
|
||||
texDisplay.typeCast = CompType::Typeless;
|
||||
|
||||
m_pDevice->RenderTexture(texDisplay);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,7 +813,7 @@ void ReplayOutput::DisplayMesh()
|
||||
|
||||
RENDERDOC_PROFILEFUNCTION();
|
||||
|
||||
ActionDescription *action = m_pRenderer->GetActionByEID(m_EventID);
|
||||
ActionDescription *action = m_pController->GetActionByEID(m_EventID);
|
||||
|
||||
if(action == NULL || m_MainOutput.outputID == 0 || m_Width <= 0 || m_Height <= 0 ||
|
||||
(m_RenderData.meshDisplay.type == MeshDataStage::Unknown) ||
|
||||
@@ -781,6 +825,7 @@ void ReplayOutput::DisplayMesh()
|
||||
m_pDevice->ClearOutputWindowDepth(m_MainOutput.outputID, 1.0f, 0);
|
||||
m_pDevice->RenderCheckerboard(RenderDoc::Inst().DarkCheckerboardColor(),
|
||||
RenderDoc::Inst().LightCheckerboardColor());
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -788,8 +833,10 @@ void ReplayOutput::DisplayMesh()
|
||||
if(m_OverlayDirty)
|
||||
{
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_WithoutDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
RefreshOverlay();
|
||||
m_pDevice->ReplayLog(m_EventID, eReplay_OnlyDraw);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
m_pDevice->BindOutputWindow(m_MainOutput.outputID, true);
|
||||
@@ -797,8 +844,10 @@ void ReplayOutput::DisplayMesh()
|
||||
|
||||
m_pDevice->RenderCheckerboard(RenderDoc::Inst().DarkCheckerboardColor(),
|
||||
RenderDoc::Inst().LightCheckerboardColor());
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
m_pDevice->ClearOutputWindowDepth(m_MainOutput.outputID, 1.0f, 0);
|
||||
m_pController->FatalErrorCheck();
|
||||
|
||||
MeshDisplay mesh = m_RenderData.meshDisplay;
|
||||
mesh.position.vertexResourceId = m_pDevice->GetLiveID(mesh.position.vertexResourceId);
|
||||
@@ -833,7 +882,7 @@ void ReplayOutput::DisplayMesh()
|
||||
{
|
||||
for(size_t i = 0; m_RenderData.meshDisplay.showWholePass && i < passEvents.size(); i++)
|
||||
{
|
||||
ActionDescription *d = m_pRenderer->GetActionByEID(passEvents[i]);
|
||||
ActionDescription *d = m_pController->GetActionByEID(passEvents[i]);
|
||||
|
||||
if(d)
|
||||
{
|
||||
@@ -842,9 +891,13 @@ void ReplayOutput::DisplayMesh()
|
||||
// get the 'most final' stage
|
||||
MeshFormat fmt = m_pDevice->GetPostVSBuffers(
|
||||
passEvents[i], inst, m_RenderData.meshDisplay.curView, MeshDataStage::GSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
if(fmt.vertexResourceId == ResourceId())
|
||||
{
|
||||
fmt = m_pDevice->GetPostVSBuffers(passEvents[i], inst, m_RenderData.meshDisplay.curView,
|
||||
MeshDataStage::VSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
fmt.meshColor = passDraws;
|
||||
|
||||
@@ -869,9 +922,13 @@ void ReplayOutput::DisplayMesh()
|
||||
// get the 'most final' stage
|
||||
MeshFormat fmt = m_pDevice->GetPostVSBuffers(
|
||||
action->eventId, inst, m_RenderData.meshDisplay.curView, MeshDataStage::GSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
if(fmt.vertexResourceId == ResourceId())
|
||||
{
|
||||
fmt = m_pDevice->GetPostVSBuffers(action->eventId, inst, m_RenderData.meshDisplay.curView,
|
||||
MeshDataStage::VSOut);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
fmt.meshColor = otherInstances;
|
||||
|
||||
@@ -885,4 +942,5 @@ void ReplayOutput::DisplayMesh()
|
||||
mesh.position.meshColor = drawItself;
|
||||
|
||||
m_pDevice->RenderMesh(m_EventID, secondaryDraws, mesh);
|
||||
m_pController->FatalErrorCheck();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user