Fetch debug messages at replay time if option is enabled

This commit is contained in:
baldurk
2019-08-27 15:27:53 +01:00
parent c7682ca7a8
commit b4a3fb4490
21 changed files with 348 additions and 177 deletions
@@ -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();
+29 -5
View File
@@ -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)
+1
View File
@@ -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();
+34 -4
View File
@@ -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;
+33 -6
View File
@@ -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)
+1
View File
@@ -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; }
+18 -8
View File
@@ -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.");
+1 -1
View File
@@ -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);
+11 -4
View File
@@ -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)
{
+2 -2
View File
@@ -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;
}
+26 -1
View File
@@ -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)
+1 -1
View File
@@ -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)
+7 -6
View File
@@ -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;
+7 -6
View File
@@ -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;
-14
View File
@@ -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
View File
@@ -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);
}
}
}
+3
View File
@@ -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);
+4 -4
View File
@@ -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 &params, 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 &params, 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;