mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
Fetch debug messages at replay time if option is enabled
This commit is contained in:
@@ -3762,6 +3762,16 @@ void WrappedID3D11DeviceContext::Serialise_DebugMessages(SerialiserType &ser)
|
||||
|
||||
SERIALISE_ELEMENT(DebugMessages);
|
||||
|
||||
// if we're using replay-time API validation, fetch messages at replay time and ignore any
|
||||
// serialised ones
|
||||
if(ser.IsReading() && IsLoading(m_State) && m_pDevice->GetReplayOptions().apiValidation)
|
||||
{
|
||||
if(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE)
|
||||
DebugMessages = m_pDevice->GetDebugMessages();
|
||||
else
|
||||
DebugMessages.clear();
|
||||
}
|
||||
|
||||
// hide empty sets of messages.
|
||||
if(ser.IsReading() && DebugMessages.empty())
|
||||
ser.Hidden();
|
||||
|
||||
@@ -786,13 +786,26 @@ std::vector<DebugMessage> WrappedID3D11Device::GetDebugMessages()
|
||||
{
|
||||
std::vector<DebugMessage> ret;
|
||||
|
||||
// if reading, m_DebugMessages will contain all the messages (we
|
||||
// don't try and fetch anything from the API). If writing,
|
||||
// m_DebugMessages will contain any manually-added messages.
|
||||
ret.swap(m_DebugMessages);
|
||||
if(IsActiveReplaying(m_State))
|
||||
{
|
||||
// once we're active replaying, m_DebugMessages will contain all the messages from loading
|
||||
// (either from the captured serialised messages, or from ourselves during replay).
|
||||
ret.swap(m_DebugMessages);
|
||||
|
||||
if(IsReplayMode(m_State))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(IsCaptureMode(m_State))
|
||||
{
|
||||
// add any manually-added messages before fetching those from the API
|
||||
ret.swap(m_DebugMessages);
|
||||
}
|
||||
|
||||
// during loading only try and fetch messages if we're doing that deliberately during replay
|
||||
if(IsLoading(m_State) && !m_ReplayOptions.apiValidation)
|
||||
return ret;
|
||||
|
||||
// during capture, and during loading if the option is enabled, we fetch messages from the API
|
||||
|
||||
if(!m_pInfoQueue)
|
||||
return ret;
|
||||
@@ -1158,8 +1171,19 @@ ReplayStatus WrappedID3D11Device::ReadLogInitialisation(RDCFile *rdc, bool store
|
||||
m_pImmediateContext->SetFrameReader(new StreamReader(reader, frameDataSize));
|
||||
|
||||
if(!IsStructuredExporting(m_State))
|
||||
{
|
||||
std::vector<DebugMessage> savedDebugMessages;
|
||||
|
||||
// save any debug messages we built up
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
|
||||
GetResourceManager()->ApplyInitialContents();
|
||||
|
||||
// restore saved messages - which implicitly discards any generated while applying initial
|
||||
// contents
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
}
|
||||
|
||||
ReplayStatus status = m_pImmediateContext->ReplayLog(m_State, 0, 0, false);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
|
||||
@@ -401,6 +401,7 @@ public:
|
||||
m_SectionVersion = sectionVersion;
|
||||
m_ReplayOptions = opts;
|
||||
}
|
||||
const ReplayOptions &GetReplayOptions() { return m_ReplayOptions; }
|
||||
uint64_t GetLogVersion() { return m_SectionVersion; }
|
||||
virtual ~WrappedID3D11Device();
|
||||
|
||||
|
||||
@@ -3846,12 +3846,18 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, I
|
||||
|
||||
UINT flags = initParams.Flags;
|
||||
|
||||
// we control the debug flag ourselves
|
||||
flags &= ~D3D11_CREATE_DEVICE_DEBUG;
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
// in development builds, always enable debug layer during replay
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
#else
|
||||
// in release builds, never enable it
|
||||
flags &= ~D3D11_CREATE_DEVICE_DEBUG;
|
||||
// in release builds, only enable it if forced by replay options
|
||||
if(opts.apiValidation)
|
||||
flags |= D3D11_CREATE_DEVICE_DEBUG;
|
||||
else
|
||||
flags &= ~D3D11_CREATE_DEVICE_DEBUG;
|
||||
#endif
|
||||
|
||||
// we should now be set up to try creating feature level 11 devices either with a selected
|
||||
@@ -3862,6 +3868,7 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, I
|
||||
// try first with the adapter, then if we were using a specific adapter try without, then last try
|
||||
// with WARP
|
||||
// within that, try to create a device at descending feature levels
|
||||
// for each attempt, if the debug layer is enabled try without it
|
||||
|
||||
for(int adapterPass = 0; adapterPass < 3; adapterPass++)
|
||||
{
|
||||
@@ -3908,9 +3915,32 @@ ReplayStatus D3D11_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, I
|
||||
if(SUCCEEDED(hr) && device)
|
||||
break;
|
||||
|
||||
RDCLOG("Device creation failed, %s", ToStr(hr).c_str());
|
||||
|
||||
SAFE_RELEASE(device);
|
||||
|
||||
// in release try to fall back to a non-debug device
|
||||
#if ENABLED(RDOC_RELEASE)
|
||||
if(flags & D3D11_CREATE_DEVICE_DEBUG)
|
||||
{
|
||||
UINT noDebugFlags = flags & ~D3D11_CREATE_DEVICE_DEBUG;
|
||||
|
||||
HRESULT hr2 = CreateDeviceAndSwapChain(adapter, driverType, NULL, noDebugFlags,
|
||||
featureLevelSubset, numFeatureLevels,
|
||||
D3D11_SDK_VERSION, NULL, NULL, &device, NULL, NULL);
|
||||
|
||||
// if we can manage to create it without debug active, do that since it's extremely unlikely
|
||||
// that any other configuration will have better luck with debug active.
|
||||
if(SUCCEEDED(hr2) && device)
|
||||
{
|
||||
RDCLOG(
|
||||
"Device creation failed with validation active - check that you have the "
|
||||
"SDK installed or Windows feature enabled to get the D3D debug layers.");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
RDCLOG("Device creation failed, %s", ToStr(hr).c_str());
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hr) && device)
|
||||
|
||||
@@ -92,6 +92,10 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(SerialiserType &se
|
||||
|
||||
if(ser.IsReading() && IsLoading(m_State))
|
||||
{
|
||||
// if we're using replay-time API validation, ignore messages from capture time
|
||||
if(m_pDevice->GetReplayOptions().apiValidation)
|
||||
DebugMessages.clear();
|
||||
|
||||
for(const DebugMessage &msg : DebugMessages)
|
||||
m_Cmd.m_EventMessages.push_back(msg);
|
||||
}
|
||||
|
||||
@@ -1415,6 +1415,11 @@ void D3D12CommandData::AddEvent()
|
||||
|
||||
apievent.callstack = m_ChunkMetadata.callstack;
|
||||
|
||||
// if we're using replay-time debug messages, fetch them now since we can do better to correlate
|
||||
// to events on replay
|
||||
if(m_pDevice->GetReplayOptions().apiValidation)
|
||||
m_EventMessages = m_pDevice->GetDebugMessages();
|
||||
|
||||
for(size_t i = 0; i < m_EventMessages.size(); i++)
|
||||
m_EventMessages[i].eventId = apievent.eventId;
|
||||
|
||||
|
||||
@@ -2072,13 +2072,26 @@ std::vector<DebugMessage> WrappedID3D12Device::GetDebugMessages()
|
||||
{
|
||||
std::vector<DebugMessage> ret;
|
||||
|
||||
// if reading, m_DebugMessages will contain all the messages (we
|
||||
// don't try and fetch anything from the API). If writing,
|
||||
// m_DebugMessages will contain any manually-added messages.
|
||||
ret.swap(m_DebugMessages);
|
||||
if(IsActiveReplaying(m_State))
|
||||
{
|
||||
// once we're active replaying, m_DebugMessages will contain all the messages from loading
|
||||
// (either from the captured serialised messages, or from ourselves during replay).
|
||||
ret.swap(m_DebugMessages);
|
||||
|
||||
if(IsReplayMode(m_State))
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(IsCaptureMode(m_State))
|
||||
{
|
||||
// add any manually-added messages before fetching those from the API
|
||||
ret.swap(m_DebugMessages);
|
||||
}
|
||||
|
||||
// during loading only try and fetch messages if we're doing that deliberately during replay
|
||||
if(IsLoading(m_State) && !m_ReplayOptions.apiValidation)
|
||||
return ret;
|
||||
|
||||
// during capture, and during loading if the option is enabled, we fetch messages from the API
|
||||
|
||||
if(!m_pInfoQueue)
|
||||
return ret;
|
||||
@@ -2144,7 +2157,10 @@ std::vector<DebugMessage> WrappedID3D12Device::GetDebugMessages()
|
||||
msg.messageID = (uint32_t)message->ID;
|
||||
msg.description = std::string(message->pDescription);
|
||||
|
||||
ret.push_back(msg);
|
||||
// during capture add all messages. Otherwise only add this message if it's different to the
|
||||
// last one - due to our replay with real and cracked lists we get many duplicated messages
|
||||
if(!IsLoading(m_State) || ret.empty() || !(ret.back() == msg))
|
||||
ret.push_back(msg);
|
||||
|
||||
SAFE_DELETE_ARRAY(msgbuf);
|
||||
}
|
||||
@@ -2928,8 +2944,19 @@ ReplayStatus WrappedID3D12Device::ReadLogInitialisation(RDCFile *rdc, bool store
|
||||
m_Queue->SetFrameReader(new StreamReader(reader, frameDataSize));
|
||||
|
||||
if(!IsStructuredExporting(m_State))
|
||||
{
|
||||
std::vector<DebugMessage> savedDebugMessages;
|
||||
|
||||
// save any debug messages we built up
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
|
||||
ApplyInitialContents();
|
||||
|
||||
// restore saved messages - which implicitly discards any generated while applying initial
|
||||
// contents
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
}
|
||||
|
||||
ReplayStatus status = m_Queue->ReplayLog(m_State, 0, 0, false);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
|
||||
@@ -513,6 +513,7 @@ public:
|
||||
m_SectionVersion = sectionVersion;
|
||||
m_ReplayOptions = opts;
|
||||
}
|
||||
const ReplayOptions &GetReplayOptions() { return m_ReplayOptions; }
|
||||
uint64_t GetLogVersion() { return m_SectionVersion; }
|
||||
CaptureState GetState() { return m_State; }
|
||||
D3D12Replay *GetReplay() { return &m_Replay; }
|
||||
|
||||
@@ -3757,20 +3757,30 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, I
|
||||
ChooseBestMatchingAdapter(GraphicsAPI::D3D12, factory, initParams.AdapterDesc, opts, NULL,
|
||||
&adapter);
|
||||
|
||||
bool EnableDebugLayer = false;
|
||||
bool debugLayerEnabled = false;
|
||||
|
||||
RDCLOG("Creating D3D12 replay device, minimum feature level %s",
|
||||
ToStr(initParams.MinimumFeatureLevel).c_str());
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
// in development builds, always enable debug layer during replay
|
||||
EnableDebugLayer = EnableD3D12DebugLayer();
|
||||
bool shouldEnableDebugLayer = opts.apiValidation;
|
||||
|
||||
RDCLOG(
|
||||
"Development RenderDoc builds require D3D debug layers available, "
|
||||
"ensure you have the windows SDK or windows feature needed.");
|
||||
// in development builds, always enable debug layer during replay
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
shouldEnableDebugLayer = true;
|
||||
#endif
|
||||
|
||||
if(shouldEnableDebugLayer)
|
||||
{
|
||||
debugLayerEnabled = EnableD3D12DebugLayer();
|
||||
|
||||
if(!debugLayerEnabled)
|
||||
{
|
||||
RDCLOG(
|
||||
"Enabling the D3D debug layers failed, "
|
||||
"ensure you have the windows SDK or windows feature needed.");
|
||||
}
|
||||
}
|
||||
|
||||
ID3D12Device *dev = NULL;
|
||||
hr = createDevice(adapter, initParams.MinimumFeatureLevel, __uuidof(ID3D12Device), (void **)&dev);
|
||||
|
||||
@@ -3795,7 +3805,7 @@ ReplayStatus D3D12_CreateReplayDevice(RDCFile *rdc, const ReplayOptions &opts, I
|
||||
return ReplayStatus::APIHardwareUnsupported;
|
||||
}
|
||||
|
||||
WrappedID3D12Device *wrappedDev = new WrappedID3D12Device(dev, initParams, EnableDebugLayer);
|
||||
WrappedID3D12Device *wrappedDev = new WrappedID3D12Device(dev, initParams, debugLayerEnabled);
|
||||
wrappedDev->SetInitParams(initParams, ver, opts);
|
||||
|
||||
RDCLOG("Created device.");
|
||||
|
||||
@@ -212,7 +212,7 @@ class CGLPlatform : public GLPlatform
|
||||
return ret;
|
||||
}
|
||||
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
|
||||
{
|
||||
RDCASSERT(api == RDCDriver::OpenGL);
|
||||
|
||||
|
||||
@@ -134,12 +134,16 @@ class EGLPlatform : public GLPlatform
|
||||
EGLDisplay eglDisplay = EGL.GetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
RDCASSERT(eglDisplay);
|
||||
|
||||
return CreateWindowingData(eglDisplay, share_context.ctx, win);
|
||||
return CreateWindowingData(eglDisplay, share_context.ctx, win, false);
|
||||
}
|
||||
|
||||
GLWindowingData CreateWindowingData(EGLDisplay eglDisplay, EGLContext share_ctx,
|
||||
EGLNativeWindowType window)
|
||||
EGLNativeWindowType window, bool debug)
|
||||
{
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
debug = true;
|
||||
#endif
|
||||
|
||||
GLWindowingData ret;
|
||||
ret.egl_dpy = eglDisplay;
|
||||
ret.egl_ctx = NULL;
|
||||
@@ -176,6 +180,9 @@ class EGLPlatform : public GLPlatform
|
||||
// first we try with the debug bit set, then if that fails we try without debug
|
||||
for(int debugPass = 0; debugPass < 2; debugPass++)
|
||||
{
|
||||
if(!debug && debugPass == 0)
|
||||
continue;
|
||||
|
||||
// don't change this ar ray without changing indices in the loop below
|
||||
EGLint verAttribs[] = {
|
||||
EGL_CONTEXT_MAJOR_VERSION_KHR,
|
||||
@@ -271,7 +278,7 @@ class EGLPlatform : public GLPlatform
|
||||
}
|
||||
|
||||
bool PopulateForReplay() { return EGL.PopulateForReplay(); }
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
|
||||
{
|
||||
// we only support replaying GLES through EGL
|
||||
RDCASSERT(api == RDCDriver::OpenGLES);
|
||||
@@ -288,7 +295,7 @@ class EGLPlatform : public GLPlatform
|
||||
int major, minor;
|
||||
EGL.Initialize(eglDisplay, &major, &minor);
|
||||
|
||||
replayContext = CreateWindowingData(eglDisplay, EGL_NO_CONTEXT, 0);
|
||||
replayContext = CreateWindowingData(eglDisplay, EGL_NO_CONTEXT, 0, debug);
|
||||
|
||||
if(!replayContext.ctx)
|
||||
{
|
||||
|
||||
@@ -289,7 +289,7 @@ struct GLPlatform
|
||||
// for initialisation at replay time
|
||||
virtual bool CanCreateGLESContext() = 0;
|
||||
virtual bool PopulateForReplay() = 0;
|
||||
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api) = 0;
|
||||
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug) = 0;
|
||||
virtual void *GetReplayFunction(const char *funcname) = 0;
|
||||
};
|
||||
|
||||
@@ -313,7 +313,7 @@ class GLDummyPlatform : public GLPlatform
|
||||
// for initialisation at replay time
|
||||
virtual bool CanCreateGLESContext() { return true; }
|
||||
virtual bool PopulateForReplay() { return true; }
|
||||
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
|
||||
virtual ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
|
||||
{
|
||||
return ReplayStatus::Succeeded;
|
||||
}
|
||||
|
||||
@@ -2629,7 +2629,15 @@ bool WrappedOpenGL::Serialise_BeginCaptureFrame(SerialiserType &ser)
|
||||
|
||||
if(IsReplayingAndReading())
|
||||
{
|
||||
std::vector<DebugMessage> savedDebugMessages;
|
||||
|
||||
// save any debug messages we built up
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
|
||||
state.ApplyState(this);
|
||||
|
||||
// restore saved messages - which implicitly discards any generated while applying state
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2702,6 +2710,14 @@ void WrappedOpenGL::Serialise_DebugMessages(SerialiserType &ser)
|
||||
|
||||
SERIALISE_ELEMENT(DebugMessages);
|
||||
|
||||
// if we're using replay-time API validation, fetch messages at replay time and ignore any
|
||||
// serialised ones
|
||||
if(ser.IsReading() && IsLoading(m_State) && m_ReplayOptions.apiValidation)
|
||||
{
|
||||
DebugMessages = m_DebugMessages;
|
||||
m_DebugMessages.clear();
|
||||
}
|
||||
|
||||
// hide empty sets of messages.
|
||||
if(ser.IsReading() && DebugMessages.empty())
|
||||
ser.Hidden();
|
||||
@@ -2767,7 +2783,7 @@ void WrappedOpenGL::DebugSnoop(GLenum source, GLenum type, GLuint id, GLenum sev
|
||||
RDCLOG("Debug Message context: \"%s\"", m_DebugMsgContext.c_str());
|
||||
}
|
||||
|
||||
if(IsActiveCapturing(m_State))
|
||||
if(IsActiveCapturing(m_State) || (IsLoading(m_State) && m_ReplayOptions.apiValidation))
|
||||
{
|
||||
DebugMessage msg;
|
||||
|
||||
@@ -2955,8 +2971,17 @@ ReplayStatus WrappedOpenGL::ReadLogInitialisation(RDCFile *rdc, bool storeStruct
|
||||
|
||||
m_FrameReader = new StreamReader(reader, frameDataSize);
|
||||
|
||||
std::vector<DebugMessage> savedDebugMessages;
|
||||
|
||||
// save any debug messages we built up
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
|
||||
GetResourceManager()->ApplyInitialContents();
|
||||
|
||||
// restore saved messages - which implicitly discards any generated while applying initial
|
||||
// contents
|
||||
savedDebugMessages.swap(m_DebugMessages);
|
||||
|
||||
ReplayStatus status = ContextReplayLog(m_State, 0, 0, false);
|
||||
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
|
||||
@@ -3415,7 +3415,7 @@ ReplayStatus CreateReplayDevice(RDCDriver rdcdriver, RDCFile *rdc, const ReplayO
|
||||
|
||||
GLWindowingData data = {};
|
||||
|
||||
ReplayStatus status = platform.InitialiseAPI(data, rdcdriver);
|
||||
ReplayStatus status = platform.InitialiseAPI(data, rdcdriver, opts.apiValidation);
|
||||
|
||||
// any errors will be already printed, just pass the error up
|
||||
if(status != ReplayStatus::Succeeded)
|
||||
|
||||
@@ -326,8 +326,13 @@ class GLXPlatform : public GLPlatform
|
||||
}
|
||||
|
||||
bool PopulateForReplay() { return GLX.PopulateForReplay(); }
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
|
||||
{
|
||||
// force debug in development builds
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
debug = true;
|
||||
#endif
|
||||
|
||||
RDCASSERT(api == RDCDriver::OpenGL || api == RDCDriver::OpenGLES);
|
||||
|
||||
int attribs[64] = {0};
|
||||
@@ -340,11 +345,7 @@ class GLXPlatform : public GLPlatform
|
||||
int &minor = attribs[i];
|
||||
attribs[i++] = 0;
|
||||
attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB;
|
||||
#else
|
||||
attribs[i++] = 0;
|
||||
#endif
|
||||
attribs[i++] = debug ? GLX_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
|
||||
attribs[i++] = api == RDCDriver::OpenGLES ? GLX_CONTEXT_ES2_PROFILE_BIT_EXT
|
||||
: GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
|
||||
@@ -291,8 +291,13 @@ class WGLPlatform : public GLPlatform
|
||||
}
|
||||
|
||||
bool PopulateForReplay() { return WGL.PopulateForReplay(); }
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api)
|
||||
ReplayStatus InitialiseAPI(GLWindowingData &replayContext, RDCDriver api, bool debug)
|
||||
{
|
||||
// force debug in development builds
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
debug = true;
|
||||
#endif
|
||||
|
||||
RDCASSERT(api == RDCDriver::OpenGL || api == RDCDriver::OpenGLES);
|
||||
|
||||
bool success = RegisterClass();
|
||||
@@ -370,11 +375,7 @@ class WGLPlatform : public GLPlatform
|
||||
int &minor = attribs[i];
|
||||
attribs[i++] = 0;
|
||||
attribs[i++] = WGL_CONTEXT_FLAGS_ARB;
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
#else
|
||||
attribs[i++] = 0;
|
||||
#endif
|
||||
attribs[i++] = debug ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
|
||||
attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
|
||||
attribs[i++] = api == RDCDriver::OpenGLES ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT
|
||||
: WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
|
||||
@@ -71,20 +71,6 @@
|
||||
// happening
|
||||
#define VERBOSE_PARTIAL_REPLAY OPTION_OFF
|
||||
|
||||
// enable this to enable validation layers on replay, useful for debugging
|
||||
// problems with new replay code
|
||||
#define FORCE_VALIDATION_LAYERS OPTION_OFF
|
||||
|
||||
// enable this to send replay-time validation layer messages to the UI.
|
||||
// By default we only display saved validation layer messages from capture, and then any runtime
|
||||
// messages we generate ourselves. With this option, every time the catpure is replayed, any
|
||||
// messages will be bubbled up and added to the list in the UI - there is no deduplication so this
|
||||
// will be an ever-growing list.
|
||||
// This is independent of FORCE_VALIDATION_LAYERS above. We will listen to debug report if it's
|
||||
// available whether or not we enabled the validation layers, and output any messages. This allows
|
||||
// the ICD to generate messages for display
|
||||
#define DISPLAY_RUNTIME_DEBUG_MESSAGES OPTION_OFF
|
||||
|
||||
ResourceFormat MakeResourceFormat(VkFormat fmt);
|
||||
VkFormat MakeVkFormat(ResourceFormat fmt);
|
||||
Topology MakePrimitiveTopology(VkPrimitiveTopology Topo, uint32_t patchControlPoints);
|
||||
|
||||
+120
-111
@@ -2087,6 +2087,10 @@ ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStruct
|
||||
|
||||
uint64_t frameDataSize = 0;
|
||||
|
||||
ScopedDebugMessageSink *sink = NULL;
|
||||
if(m_ReplayOptions.apiValidation)
|
||||
sink = new ScopedDebugMessageSink(this);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
PerformanceTimer timer;
|
||||
@@ -2145,6 +2149,8 @@ ReplayStatus WrappedVulkan::ReadLogInitialisation(RDCFile *rdc, bool storeStruct
|
||||
break;
|
||||
}
|
||||
|
||||
SAFE_DELETE(sink);
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
for(auto it = chunkInfos.begin(); it != chunkInfos.end(); ++it)
|
||||
{
|
||||
@@ -2236,10 +2242,16 @@ ReplayStatus WrappedVulkan::ContextReplayLog(CaptureState readType, uint32_t sta
|
||||
// (not undefined)
|
||||
if(IsLoading(m_State))
|
||||
{
|
||||
// temporarily disable the debug message sink, to ignore messages from initial contents apply
|
||||
ScopedDebugMessageSink *sink = GetDebugMessageSink();
|
||||
SetDebugMessageSink(NULL);
|
||||
|
||||
ApplyInitialContents();
|
||||
|
||||
SubmitCmds();
|
||||
FlushQ();
|
||||
|
||||
SetDebugMessageSink(sink);
|
||||
}
|
||||
|
||||
m_RootEvents.clear();
|
||||
@@ -2470,28 +2482,7 @@ bool WrappedVulkan::ContextProcessChunk(ReadSerialiser &ser, VulkanChunk chunk)
|
||||
{
|
||||
m_AddedDrawcall = false;
|
||||
|
||||
bool success = false;
|
||||
|
||||
#if ENABLED(DISPLAY_RUNTIME_DEBUG_MESSAGES)
|
||||
// see the definition of DISPLAY_RUNTIME_DEBUG_MESSAGES for more information. During replay, add a
|
||||
// debug sink to catch any replay-time messages
|
||||
{
|
||||
ScopedDebugMessageSink sink(this);
|
||||
|
||||
success = ProcessChunk(ser, chunk);
|
||||
|
||||
if(IsActiveReplaying(m_State))
|
||||
{
|
||||
std::vector<DebugMessage> DebugMessages;
|
||||
DebugMessages.swap(sink.msgs);
|
||||
|
||||
for(const DebugMessage &msg : DebugMessages)
|
||||
AddDebugMessage(msg);
|
||||
}
|
||||
}
|
||||
#else
|
||||
success = ProcessChunk(ser, chunk);
|
||||
#endif
|
||||
bool success = ProcessChunk(ser, chunk);
|
||||
|
||||
if(!success)
|
||||
return false;
|
||||
@@ -3223,98 +3214,16 @@ void WrappedVulkan::Serialise_DebugMessages(SerialiserType &ser)
|
||||
if(sink)
|
||||
DebugMessages.swap(sink->msgs);
|
||||
|
||||
// if we have the unique objects layer we can assume all objects have a unique ID, and replace
|
||||
// any text that looks like an object reference (0xHEX[NAME]).
|
||||
if(m_LayersEnabled[VkCheckLayer_unique_objects])
|
||||
{
|
||||
for(DebugMessage &msg : DebugMessages)
|
||||
{
|
||||
if(strstr(msg.description.c_str(), "0x"))
|
||||
{
|
||||
std::string desc = msg.description;
|
||||
|
||||
size_t offs = desc.find("0x");
|
||||
while(offs != std::string::npos)
|
||||
{
|
||||
// if we're on a word boundary
|
||||
if(offs == 0 || !isalnum(desc[offs - 1]))
|
||||
{
|
||||
size_t end = offs + 2;
|
||||
|
||||
uint64_t val = 0;
|
||||
|
||||
// consume all hex chars
|
||||
while(end < desc.length())
|
||||
{
|
||||
if(desc[end] >= '0' && desc[end] <= '9')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - '0');
|
||||
end++;
|
||||
}
|
||||
else if(desc[end] >= 'A' && desc[end] <= 'F')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - 'A') + 0xA;
|
||||
end++;
|
||||
}
|
||||
else if(desc[end] >= 'a' && desc[end] <= 'f')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - 'a') + 0xA;
|
||||
end++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we now expect a [NAME]. Look for matched set of []s
|
||||
if(desc[end] == '[')
|
||||
{
|
||||
int depth = 1;
|
||||
end++;
|
||||
|
||||
while(end < desc.length() && depth)
|
||||
{
|
||||
if(desc[end] == '[')
|
||||
depth++;
|
||||
else if(desc[end] == ']')
|
||||
depth--;
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
// unique objects layer implies this is a unique search so we don't have to worry
|
||||
// about type aliases
|
||||
ResourceId id = GetResourceManager()->GetFirstIDForHandle(val);
|
||||
|
||||
if(id != ResourceId())
|
||||
{
|
||||
std::string idstr = ToStr(id);
|
||||
|
||||
desc.erase(offs, end - offs);
|
||||
|
||||
desc.insert(offs, idstr.c_str());
|
||||
|
||||
offs = desc.find("0x", offs + idstr.length());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offs = desc.find("0x", offs + 1);
|
||||
}
|
||||
|
||||
msg.description = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(DebugMessage &msg : DebugMessages)
|
||||
ProcessDebugMessage(msg);
|
||||
}
|
||||
|
||||
SERIALISE_ELEMENT(DebugMessages);
|
||||
|
||||
// if we're using debug messages from replay, discard any from the capture
|
||||
if(ser.IsReading() && IsLoading(m_State) && m_ReplayOptions.apiValidation)
|
||||
DebugMessages.clear();
|
||||
|
||||
// hide empty sets of messages.
|
||||
if(ser.IsReading() && DebugMessages.empty())
|
||||
ser.Hidden();
|
||||
@@ -3329,6 +3238,95 @@ void WrappedVulkan::Serialise_DebugMessages(SerialiserType &ser)
|
||||
template void WrappedVulkan::Serialise_DebugMessages(WriteSerialiser &ser);
|
||||
template void WrappedVulkan::Serialise_DebugMessages(ReadSerialiser &ser);
|
||||
|
||||
void WrappedVulkan::ProcessDebugMessage(DebugMessage &msg)
|
||||
{
|
||||
// if we have the unique objects layer we can assume all objects have a unique ID, and replace
|
||||
// any text that looks like an object reference (0xHEX[NAME]).
|
||||
if(m_LayersEnabled[VkCheckLayer_unique_objects])
|
||||
{
|
||||
if(strstr(msg.description.c_str(), "0x"))
|
||||
{
|
||||
std::string desc = msg.description;
|
||||
|
||||
size_t offs = desc.find("0x");
|
||||
while(offs != std::string::npos)
|
||||
{
|
||||
// if we're on a word boundary
|
||||
if(offs == 0 || !isalnum(desc[offs - 1]))
|
||||
{
|
||||
size_t end = offs + 2;
|
||||
|
||||
uint64_t val = 0;
|
||||
|
||||
// consume all hex chars
|
||||
while(end < desc.length())
|
||||
{
|
||||
if(desc[end] >= '0' && desc[end] <= '9')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - '0');
|
||||
end++;
|
||||
}
|
||||
else if(desc[end] >= 'A' && desc[end] <= 'F')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - 'A') + 0xA;
|
||||
end++;
|
||||
}
|
||||
else if(desc[end] >= 'a' && desc[end] <= 'f')
|
||||
{
|
||||
val <<= 4;
|
||||
val += (desc[end] - 'a') + 0xA;
|
||||
end++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we now expect a [NAME]. Look for matched set of []s
|
||||
if(desc[end] == '[')
|
||||
{
|
||||
int depth = 1;
|
||||
end++;
|
||||
|
||||
while(end < desc.length() && depth)
|
||||
{
|
||||
if(desc[end] == '[')
|
||||
depth++;
|
||||
else if(desc[end] == ']')
|
||||
depth--;
|
||||
|
||||
end++;
|
||||
}
|
||||
|
||||
// unique objects layer implies this is a unique search so we don't have to worry
|
||||
// about type aliases
|
||||
ResourceId id = GetResourceManager()->GetFirstIDForHandle(val);
|
||||
|
||||
if(id != ResourceId())
|
||||
{
|
||||
std::string idstr = ToStr(id);
|
||||
|
||||
desc.erase(offs, end - offs);
|
||||
|
||||
desc.insert(offs, idstr.c_str());
|
||||
|
||||
offs = desc.find("0x", offs + idstr.length());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offs = desc.find("0x", offs + 1);
|
||||
}
|
||||
|
||||
msg.description = desc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DebugMessage> WrappedVulkan::GetDebugMessages()
|
||||
{
|
||||
std::vector<DebugMessage> ret;
|
||||
@@ -3396,7 +3394,18 @@ VkBool32 WrappedVulkan::DebugCallback(MessageSeverity severity, MessageCategory
|
||||
msg.eventId = it->eventId;
|
||||
}
|
||||
|
||||
sink->msgs.push_back(msg);
|
||||
// function calls are replayed after the call to Serialise_DebugMessages() so we don't have a
|
||||
// sync point to gather together all the messages from the sink. But instead we can just push
|
||||
// them directly into the list since we're linearised
|
||||
if(IsReplayMode(m_State))
|
||||
{
|
||||
ProcessDebugMessage(msg);
|
||||
AddDebugMessage(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
sink->msgs.push_back(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -246,6 +246,9 @@ private:
|
||||
std::vector<DebugMessage> m_DebugMessages;
|
||||
template <typename SerialiserType>
|
||||
void Serialise_DebugMessages(SerialiserType &ser);
|
||||
|
||||
void ProcessDebugMessage(DebugMessage &DebugMessages);
|
||||
|
||||
std::vector<DebugMessage> GetDebugMessages();
|
||||
void AddDebugMessage(DebugMessage msg);
|
||||
void AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src, std::string d);
|
||||
|
||||
@@ -747,9 +747,9 @@ void VulkanResourceManager::ApplyBarriers(uint32_t queueFamilyIndex,
|
||||
|
||||
ResourceId VulkanResourceManager::GetFirstIDForHandle(uint64_t handle)
|
||||
{
|
||||
for(auto it = m_ResourceRecords.begin(); it != m_ResourceRecords.end(); ++it)
|
||||
for(auto it = m_CurrentResourceMap.begin(); it != m_CurrentResourceMap.end(); ++it)
|
||||
{
|
||||
WrappedVkRes *res = it->second->Resource;
|
||||
WrappedVkRes *res = it->second;
|
||||
|
||||
if(!res)
|
||||
continue;
|
||||
@@ -758,13 +758,13 @@ ResourceId VulkanResourceManager::GetFirstIDForHandle(uint64_t handle)
|
||||
{
|
||||
WrappedVkDispRes *disp = (WrappedVkDispRes *)res;
|
||||
if(disp->real.handle == handle)
|
||||
return disp->id;
|
||||
return IsReplayMode(m_State) ? GetOriginalID(disp->id) : disp->id;
|
||||
}
|
||||
else
|
||||
{
|
||||
WrappedVkNonDispRes *nondisp = (WrappedVkNonDispRes *)res;
|
||||
if(nondisp->real.handle == handle)
|
||||
return nondisp->id;
|
||||
return IsReplayMode(m_State) ? GetOriginalID(nondisp->id) : nondisp->id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,10 +180,6 @@ ReplayStatus WrappedVulkan::Initialise(VkInitParams ¶ms, uint64_t sectionVer
|
||||
StripUnwantedLayers(params.Layers);
|
||||
StripUnwantedExtensions(params.Extensions);
|
||||
|
||||
#if ENABLED(FORCE_VALIDATION_LAYERS) && DISABLED(RDOC_ANDROID)
|
||||
params.Layers.push_back("VK_LAYER_LUNARG_standard_validation");
|
||||
#endif
|
||||
|
||||
std::set<std::string> supportedLayers;
|
||||
|
||||
{
|
||||
@@ -199,6 +195,29 @@ ReplayStatus WrappedVulkan::Initialise(VkInitParams ¶ms, uint64_t sectionVer
|
||||
SAFE_DELETE_ARRAY(props);
|
||||
}
|
||||
|
||||
if(m_ReplayOptions.apiValidation)
|
||||
{
|
||||
const char KhronosValidation[] = "VK_LAYER_KHRONOS_validation";
|
||||
const char LunarGValidation[] = "VK_LAYER_LUNARG_standard_validation";
|
||||
|
||||
if(supportedLayers.find(KhronosValidation) != supportedLayers.end())
|
||||
{
|
||||
RDCLOG("Enabling %s layer for API validation", KhronosValidation);
|
||||
params.Layers.push_back(KhronosValidation);
|
||||
m_LayersEnabled[VkCheckLayer_unique_objects] = true;
|
||||
}
|
||||
else if(supportedLayers.find(LunarGValidation) != supportedLayers.end())
|
||||
{
|
||||
RDCLOG("Enabling %s layer for API validation", LunarGValidation);
|
||||
params.Layers.push_back(LunarGValidation);
|
||||
m_LayersEnabled[VkCheckLayer_unique_objects] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCLOG("API validation layers are not available, check you have the Vulkan SDK installed");
|
||||
}
|
||||
}
|
||||
|
||||
// complain about any missing layers, but remove them from the list and continue
|
||||
for(auto it = params.Layers.begin(); it != params.Layers.end();)
|
||||
{
|
||||
@@ -614,6 +633,7 @@ VkResult WrappedVulkan::vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo
|
||||
for(uint32_t i = 0; i < modifiedCreateInfo.enabledLayerCount; i++)
|
||||
{
|
||||
if(!strcmp(modifiedCreateInfo.ppEnabledLayerNames[i], "VK_LAYER_LUNARG_standard_validation") ||
|
||||
!strcmp(modifiedCreateInfo.ppEnabledLayerNames[i], "VK_LAYER_KHRONOS_validation") ||
|
||||
!strcmp(modifiedCreateInfo.ppEnabledLayerNames[i], "VK_LAYER_GOOGLE_unique_objects"))
|
||||
{
|
||||
m_LayersEnabled[VkCheckLayer_unique_objects] = true;
|
||||
@@ -2603,11 +2623,18 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi
|
||||
|
||||
APIProps.vendor = GetDriverInfo().Vendor();
|
||||
|
||||
// temporarily disable the debug message sink, to ignore any false positive messages from our
|
||||
// init
|
||||
ScopedDebugMessageSink *sink = GetDebugMessageSink();
|
||||
SetDebugMessageSink(NULL);
|
||||
|
||||
m_ShaderCache = new VulkanShaderCache(this);
|
||||
|
||||
m_DebugManager = new VulkanDebugManager(this);
|
||||
|
||||
m_Replay.CreateResources();
|
||||
|
||||
SetDebugMessageSink(sink);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user