glave: Register a handler in replayer for error msg callbacks and report these
Hook up DbgMsgCallbacks from validation layers to replayer. Log Warnings
and Info messages. For Error messages log them and also fail the replay of
the packet that caused it.
By default enable debug level 4 in debugger and layers MemTracker and DrawState.
diff --git a/glave-generate.py b/glave-generate.py
index f93f27e..e29fae6 100755
--- a/glave-generate.py
+++ b/glave-generate.py
@@ -1325,6 +1325,8 @@
cd_body.append(' virtual ~ApiReplay() { }')
cd_body.append(' virtual enum glv_replay::GLV_REPLAY_RESULT replay(glv_trace_packet_header * packet) = 0;')
cd_body.append(' virtual int init(glv_replay::Display & disp) = 0;')
+ cd_body.append(' virtual void push_validation_msg(XGL_VALIDATION_LEVEL validationLevel, XGL_BASE_OBJECT srcObject, XGL_SIZE location, XGL_INT msgCode, const char* pMsg) = 0;')
+ cd_body.append(' virtual glv_replay::GLV_REPLAY_RESULT pop_validation_msgs() = 0;')
cd_body.append('};\n')
cd_body.append('class xglDisplay: public glv_replay::DisplayImp {')
cd_body.append('friend class xglReplay;')
@@ -1441,6 +1443,8 @@
rc_body.append(' xglDisplay * get_display() {return m_display;}')
rc_body.append(' glv_replay::GLV_REPLAY_RESULT replay(glv_trace_packet_header *packet);')
rc_body.append(' glv_replay::GLV_REPLAY_RESULT handle_replay_errors(const char* entrypointName, const XGL_RESULT resCall, const XGL_RESULT resTrace, const glv_replay::GLV_REPLAY_RESULT resIn);\n')
+ rc_body.append(' void push_validation_msg(XGL_VALIDATION_LEVEL validationLevel, XGL_BASE_OBJECT srcObject, XGL_SIZE location, XGL_INT msgCode, const char* pMsg);')
+ rc_body.append(' glv_replay::GLV_REPLAY_RESULT pop_validation_msgs();')
rc_body.append('private:')
rc_body.append(' struct xglFuncs m_xglFuncs;')
rc_body.append(' void copy_mem_remap_range_struct(XGL_VIRTUAL_MEMORY_REMAP_RANGE *outRange, const XGL_VIRTUAL_MEMORY_REMAP_RANGE *inRange);')
@@ -1451,6 +1455,14 @@
rc_body.append(' XGL_SHADER *addr;')
rc_body.append(' XGL_SHADER val;')
rc_body.append(' };')
+ rc_body.append(' struct validationMsg {')
+ rc_body.append(' XGL_VALIDATION_LEVEL validationLevel;')
+ rc_body.append(' XGL_BASE_OBJECT srcObject;')
+ rc_body.append(' XGL_SIZE location;')
+ rc_body.append(' XGL_INT msgCode;')
+ rc_body.append(' char msg[256];')
+ rc_body.append(' };')
+ rc_body.append(' std::vector<struct validationMsg> m_validationMsgs;')
rc_body.append(self._map_decl('XGL_GPU_MEMORY', 'XGLAllocInfo', 'm_mapData'))
# Custom code for 1-off memory mapping functions
rc_body.append(' void add_entry_to_mapData(XGL_GPU_MEMORY handle, XGL_GPU_SIZE size)')
@@ -1904,6 +1916,28 @@
re_body.append('}')
return "\n".join(re_body)
+ def _generate_replay_validation_funcs(self):
+ rvf_body = []
+ rvf_body.append('void xglReplay::push_validation_msg(XGL_VALIDATION_LEVEL validationLevel, XGL_BASE_OBJECT srcObject, XGL_SIZE location, XGL_INT msgCode, const char * pMsg)')
+ rvf_body.append('{')
+ rvf_body.append(' struct validationMsg msgObj;')
+ rvf_body.append(' msgObj.validationLevel = validationLevel;')
+ rvf_body.append(' msgObj.srcObject = srcObject;')
+ rvf_body.append(' msgObj.location = location;')
+ rvf_body.append(' msgObj.msgCode = msgCode;')
+ rvf_body.append(' strncpy(msgObj.msg, pMsg, 256);')
+ rvf_body.append(" msgObj.msg[255] = '\\0';")
+ rvf_body.append(' m_validationMsgs.push_back(msgObj);')
+ rvf_body.append('}\n')
+ rvf_body.append('glv_replay::GLV_REPLAY_RESULT xglReplay::pop_validation_msgs()')
+ rvf_body.append('{')
+ rvf_body.append(' if (m_validationMsgs.size() == 0)')
+ rvf_body.append(' return glv_replay::GLV_REPLAY_SUCCESS;')
+ rvf_body.append(' m_validationMsgs.clear();')
+ rvf_body.append(' return glv_replay::GLV_REPLAY_VALIDATION_ERROR;')
+ rvf_body.append('}')
+ return "\n".join(rvf_body)
+
def _generate_replay_init_funcs(self):
rif_body = []
rif_body.append('void xglFuncs::init_funcs(void * handle)\n{\n m_libHandle = handle;')
@@ -2073,15 +2107,30 @@
cd_body.append(' if (!m_display->m_initedXGL)')
cd_body.append(' {')
cd_body.append(' XGL_DEVICE device;')
- cd_body.append(' XGL_DEVICE_CREATE_INFO cInfo;')
cd_body.append(' if (m_debugLevel > 0)')
cd_body.append(' {')
+ cd_body.append(' XGL_DEVICE_CREATE_INFO cInfo, *ci;')
+ cd_body.append(' // TODO what is the real list of layers to be running with??')
+ cd_body.append(' const XGL_CHAR * layersStr[2] = {(XGL_CHAR *) "DrawState", (XGL_CHAR *) "MemTracker"};')
+ cd_body.append(' XGL_LAYER_CREATE_INFO layerInfo;')
+ cd_body.append(' ci = (XGL_DEVICE_CREATE_INFO *) pPacket->pCreateInfo;')
+ cd_body.append(' while (ci->pNext != NULL)')
+ cd_body.append(' ci = (XGL_DEVICE_CREATE_INFO *) ci->pNext;')
+ cd_body.append(' ci->pNext = &layerInfo;')
+ cd_body.append(' layerInfo.sType = XGL_STRUCTURE_TYPE_LAYER_CREATE_INFO;')
+ cd_body.append(' layerInfo.pNext = 0;')
+ cd_body.append(' layerInfo.layerCount = 2;')
+ cd_body.append(' layerInfo.ppActiveLayerNames = layersStr;')
cd_body.append(' memcpy(&cInfo, pPacket->pCreateInfo, sizeof(XGL_DEVICE_CREATE_INFO));')
cd_body.append(' cInfo.flags = pPacket->pCreateInfo->flags | XGL_DEVICE_CREATE_VALIDATION_BIT;')
cd_body.append(' cInfo.maxValidationLevel = (XGL_VALIDATION_LEVEL)((m_debugLevel <= 4) ? XGL_VALIDATION_LEVEL_0 + m_debugLevel : XGL_VALIDATION_LEVEL_0);')
cd_body.append(' pPacket->pCreateInfo = &cInfo;')
+ cd_body.append(' replayResult = m_xglFuncs.real_xglCreateDevice(remap(pPacket->gpu), pPacket->pCreateInfo, &device);')
+ cd_body.append(' if (xglDbgRegisterMsgCallback(g_fpDbgMsgCallback, NULL) != XGL_SUCCESS)')
+ cd_body.append(' glv_LogError("Failed to register xgl callback for replayer error handling\\n");')
cd_body.append(' }')
- cd_body.append(' replayResult = m_xglFuncs.real_xglCreateDevice(remap(pPacket->gpu), pPacket->pCreateInfo, &device);')
+ cd_body.append(' else ')
+ cd_body.append(' replayResult = m_xglFuncs.real_xglCreateDevice(remap(pPacket->gpu), pPacket->pCreateInfo, &device);')
cd_body.append(' CHECK_RETURN_VALUE(xglCreateDevice);')
cd_body.append(' if (replayResult == XGL_SUCCESS)')
cd_body.append(' {')
@@ -2858,6 +2907,7 @@
def generate_header(self):
header_txt = []
header_txt.append('#include "glvreplay_xgl_replay.h"\n')
+ header_txt.append('#include "glvreplay_xgl.h"\n')
header_txt.append('extern "C" {')
header_txt.append('#include "glvtrace_xgl_xgl_structs.h"')
header_txt.append('#include "glvtrace_xgl_xgldbg_structs.h"')
@@ -2888,6 +2938,7 @@
self._generate_replay_init(),
self._generate_replay_remap(),
self._generate_replay_errors(),
+ self._generate_replay_validation_funcs(),
self._generate_replay_init_funcs(),
self._generate_replay()]
diff --git a/tools/glave/src/glv_extensions/glvreplay_xgl/CMakeLists.txt b/tools/glave/src/glv_extensions/glvreplay_xgl/CMakeLists.txt
index ee7fc77..dbb8859 100644
--- a/tools/glave/src/glv_extensions/glvreplay_xgl/CMakeLists.txt
+++ b/tools/glave/src/glv_extensions/glvreplay_xgl/CMakeLists.txt
@@ -7,7 +7,7 @@
include("${SRC_DIR}/build_options.cmake")
-include_directories(${CMAKE_CURRENT_BINARY_DIR} ${SRC_DIR}/../../../include)
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${SRC_DIR}/../../../include ${SRC_DIR}/glv_extensions/glvreplay_xgl)
# This file is shared between replayer and tracer and are generated to each dir. Should generate them to common area
add_custom_command(OUTPUT glvtrace_xgl_packet_id.h xgl_enum_string_helper.h glvtrace_xgl_xgl_structs.h glvtrace_xgl_xglwsix11ext_structs.h glvtrace_xgl_xgldbg_structs.h glvreplay_xgl_replay.h glvreplay_xgl_replay.cpp
diff --git a/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.cpp b/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.cpp
index 8c5b958..c27fe54 100644
--- a/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.cpp
+++ b/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.cpp
@@ -31,6 +31,37 @@
}
ApiReplay* g_pReplayer = NULL;
+GLV_CRITICAL_SECTION g_handlerLock;
+XGL_DBG_MSG_CALLBACK_FUNCTION g_fpDbgMsgCallback;
+
+static XGL_VOID xglErrorHandler(
+ XGL_DBG_MSG_TYPE msgType,
+ XGL_VALIDATION_LEVEL validationLevel,
+ XGL_BASE_OBJECT srcObject,
+ XGL_SIZE location,
+ XGL_INT msgCode,
+ const XGL_CHAR* pMsg,
+ XGL_VOID* pUserData)
+{
+ glv_enter_critical_section(&g_handlerLock);
+ switch (msgType) {
+ case XGL_DBG_MSG_ERROR:
+ glv_LogError("Validation level %d with object %p, location %u returned msgCode %d and msg %s\n",
+ validationLevel, srcObject, location, msgCode, (char *) pMsg);
+ g_pReplayer->push_validation_msg(validationLevel, srcObject, location, msgCode, (char *) pMsg);
+ break;
+ case XGL_DBG_MSG_WARNING:
+ case XGL_DBG_MSG_PERF_WARNING:
+ glv_LogWarn("Validation level %d with object %p, location %u returned msgCode %d and msg %s\n",
+ validationLevel, srcObject, location, msgCode, (char *) pMsg);
+ break;
+ default:
+ glv_LogWarn("Validation level %d with object %p, location %u returned msgCode %d and msg %s\n",
+ validationLevel, srcObject, location, msgCode, (char *) pMsg);
+ break;
+ }
+ glv_leave_critical_section(&g_handlerLock);
+}
extern "C"
{
@@ -46,6 +77,8 @@
return -1;
}
+ glv_create_critical_section(&g_handlerLock);
+ g_fpDbgMsgCallback = xglErrorHandler;
int result = g_pReplayer->init(*pDisplay);
return result;
}
@@ -56,7 +89,10 @@
{
delete g_pReplayer;
g_pReplayer = NULL;
+ if (xglDbgUnregisterMsgCallback(g_fpDbgMsgCallback) != XGL_SUCCESS)
+ glv_LogError("Failed to unregister xgl callback for replayer\n");
}
+ glv_delete_critical_section(&g_handlerLock);
}
GLVTRACER_EXPORT glv_trace_packet_header* GLVTRACER_CDECL Interpret(glv_trace_packet_header* pPacket)
@@ -77,6 +113,9 @@
if (g_pReplayer != NULL)
{
result = g_pReplayer->replay(pPacket);
+
+ if (result == glv_replay::GLV_REPLAY_SUCCESS)
+ result = g_pReplayer->pop_validation_msgs();
}
return result;
}
diff --git a/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.h b/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.h
index 056c8e4..0375308 100644
--- a/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.h
+++ b/tools/glave/src/glv_extensions/glvreplay_xgl/glvreplay_xgl.h
@@ -25,6 +25,7 @@
#pragma once
#include "glvreplay_window.h"
#include "glvreplay_factory.h"
+#include "xglDbg.h"
extern "C"
{
@@ -33,3 +34,5 @@
GLVTRACER_EXPORT glv_trace_packet_header* GLVTRACER_CDECL Interpret(glv_trace_packet_header* pPacket);
GLVTRACER_EXPORT glv_replay::GLV_REPLAY_RESULT GLVTRACER_CDECL Replay(glv_trace_packet_header* pPacket);
}
+
+extern XGL_DBG_MSG_CALLBACK_FUNCTION g_fpDbgMsgCallback;
\ No newline at end of file
diff --git a/tools/glave/src/glvdebug/glvdebug_QReplayWorker.h b/tools/glave/src/glvdebug/glvdebug_QReplayWorker.h
index b39d252..c780f16 100644
--- a/tools/glave/src/glvdebug/glvdebug_QReplayWorker.h
+++ b/tools/glave/src/glvdebug/glvdebug_QReplayWorker.h
@@ -179,7 +179,7 @@
windowHeight = pReplayWidget->geometry().height();
// load any API specific driver libraries and init replayer objects
- int debuglevel = 0;
+ int debuglevel = 4;
uint8_t tidApi = GLV_TID_RESERVED;
// uncomment this to display in a separate window (and then comment out the line below it)
diff --git a/tools/glave/src/glvreplay/glvreplay_factory.h b/tools/glave/src/glvreplay/glvreplay_factory.h
index 1bb1253..6546657 100644
--- a/tools/glave/src/glvreplay/glvreplay_factory.h
+++ b/tools/glave/src/glvreplay/glvreplay_factory.h
@@ -40,6 +40,7 @@
GLV_REPLAY_BAD_RETURN, // replay return value != trace return value
GLV_REPLAY_CALL_ERROR, // replaying call caused an error
GLV_REPLAY_INVALID_PARAMS, // trace file parameters are invalid
+ GLV_REPLAY_VALIDATION_ERROR // callback Msg error from validation layer
};
// entrypoints that must be exposed by each replayer library