layers: DrawState layer can dump complete State to Graphviz dot file format
DrawState features "drawStateDumpDotFile(char* filename)" extension which will trigger a dot file to be dumped including PSO, Descriptor Sets, and Dynamic State.
As a convenience, DrawState will dump pipeline_dump.dot automatically on first draw only. There are a few hacks to pull off the connection of Descriptor Set to the mapping, but for all of our tests this seems to be working.
Also fixed a few DrawState hangs due to mutex locking bugs.
diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt
index 53b8947..95a048c 100644
--- a/layers/CMakeLists.txt
+++ b/layers/CMakeLists.txt
@@ -1,9 +1,10 @@
cmake_minimum_required (VERSION 2.8.11)
-add_custom_command(OUTPUT generic_layer.c xgl_enum_string_helper.h xgl_struct_string_helper.h xgl_struct_string_helper_no_addr.h api_dump.c api_dump_file.c api_dump_no_addr.c object_track.c
+add_custom_command(OUTPUT generic_layer.c xgl_enum_string_helper.h xgl_struct_string_helper.h xgl_struct_graphviz_helper.h xgl_struct_string_helper_no_addr.h api_dump.c api_dump_file.c api_dump_no_addr.c object_track.c
COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py Generic > generic_layer.c
COMMAND ${PROJECT_SOURCE_DIR}/xgl-helper.py --gen_enum_string_helper ${PROJECT_SOURCE_DIR}/include/xgl.h --abs_out_dir ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${PROJECT_SOURCE_DIR}/xgl-helper.py --gen_struct_wrappers ${PROJECT_SOURCE_DIR}/include/xgl.h --abs_out_dir ${CMAKE_CURRENT_BINARY_DIR}
+ COMMAND ${PROJECT_SOURCE_DIR}/xgl-helper.py --gen_graphviz ${PROJECT_SOURCE_DIR}/include/xgl.h --abs_out_dir ${CMAKE_CURRENT_BINARY_DIR}
COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ApiDump > api_dump.c
COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ApiDumpFile > api_dump_file.c
COMMAND ${PROJECT_SOURCE_DIR}/xgl-layer-generate.py ApiDumpNoAddr > api_dump_no_addr.c
@@ -28,5 +29,5 @@
add_library (XGLLayerAPIDump SHARED api_dump.c xgl_enum_string_helper.h xgl_struct_string_helper.h)
add_library (XGLLayerAPIDumpFile SHARED api_dump_file.c xgl_enum_string_helper.h xgl_struct_string_helper.h)
add_library (XGLLayerAPIDumpNoAddr SHARED api_dump_no_addr.c xgl_enum_string_helper.h xgl_struct_string_helper_no_addr.h)
-add_library (XGLLayerDrawState SHARED draw_state.c xgl_enum_string_helper.h xgl_struct_string_helper.h)
+add_library (XGLLayerDrawState SHARED draw_state.c xgl_enum_string_helper.h xgl_struct_string_helper.h xgl_struct_string_helper.h)
add_library (XGLLayerMemTracker SHARED mem_tracker.c xgl_enum_string_helper.h xgl_struct_string_helper.h)
diff --git a/layers/draw_state.c b/layers/draw_state.c
index 1ea8782..bffad7f 100644
--- a/layers/draw_state.c
+++ b/layers/draw_state.c
@@ -28,6 +28,7 @@
#include <assert.h>
#include <pthread.h>
#include "xgl_struct_string_helper.h"
+#include "xgl_struct_graphviz_helper.h"
#include "draw_state.h"
static XGL_LAYER_DISPATCH_TABLE nextTable;
@@ -47,7 +48,6 @@
const XGL_CHAR* pLayerPrefix,
const XGL_CHAR* pMsg)
{
- pthread_mutex_lock(&globalLock);
XGL_LAYER_DBG_FUNCTION_NODE *pTrav = pDbgFunctionHead;
if (pTrav) {
while (pTrav) {
@@ -71,7 +71,6 @@
break;
}
}
- pthread_mutex_unlock(&globalLock);
}
// Return the size of the underlying struct based on struct type
static XGL_SIZE sTypeStructSize(XGL_STRUCTURE_TYPE sType)
@@ -216,6 +215,8 @@
} DYNAMIC_STATE_NODE;
// TODO : Should be tracking lastBound per cmdBuffer and when draws occur, report based on that cmd buffer lastBound
+// Then need to synchronize the accesses based on cmd buffer so that if I'm reading state on one cmd buffer, updates
+// to that same cmd buffer by separate thread are not changing state from underneath us
static PIPELINE_NODE *pPipelineHead = NULL;
static SAMPLER_NODE *pSamplerHead = NULL;
static XGL_PIPELINE lastBoundPipeline = NULL;
@@ -329,6 +330,8 @@
// Typically pNext is const so have to cast to avoid warning when we modify it here
memcpy((void*)pShadowTrav->pNext, pTrav, sTypeStructSize(pTrav->sType));
pShadowTrav = (PIPELINE_LL_HEADER*)pShadowTrav->pNext;
+ // For deep copy DS Mapping into shadow
+ XGL_PIPELINE_SHADER_STAGE_CREATE_INFO *pShadowShaderCI = (XGL_PIPELINE_SHADER_STAGE_CREATE_INFO*)pShadowTrav;
// TODO : Now that we shadow whole create info, the special copies are just a convenience that can be done away with once shadow is complete and correct
// Special copy of DS Mapping info
if (XGL_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO == pTrav->sType) {
@@ -341,9 +344,13 @@
pSSCI->shader.descriptorSetMapping[i].descriptorCount = 0;
}
pPipeline->dsMapping[pSSCI->shader.stage][i].slotCount = pSSCI->shader.descriptorSetMapping[i].descriptorCount;
- // Deep copy DS Slot array
+ // Deep copy DS Slot array into our shortcut data structure
pPipeline->dsMapping[pSSCI->shader.stage][i].pShaderMappingSlot = (XGL_DESCRIPTOR_SLOT_INFO*)malloc(sizeof(XGL_DESCRIPTOR_SLOT_INFO)*pPipeline->dsMapping[pSSCI->shader.stage][i].slotCount);
memcpy(pPipeline->dsMapping[pSSCI->shader.stage][i].pShaderMappingSlot, pSSCI->shader.descriptorSetMapping[i].pDescriptorInfo, sizeof(XGL_DESCRIPTOR_SLOT_INFO)*pPipeline->dsMapping[pSSCI->shader.stage][i].slotCount);
+ // Deep copy into shadow tree
+ pShadowShaderCI->shader.descriptorSetMapping[i].descriptorCount = pSSCI->shader.descriptorSetMapping[i].descriptorCount;
+ pShadowShaderCI->shader.descriptorSetMapping[i].pDescriptorInfo = (XGL_DESCRIPTOR_SLOT_INFO*)malloc(sizeof(XGL_DESCRIPTOR_SLOT_INFO)*pShadowShaderCI->shader.descriptorSetMapping[i].descriptorCount);
+ memcpy((XGL_DESCRIPTOR_SLOT_INFO*)pShadowShaderCI->shader.descriptorSetMapping[i].pDescriptorInfo, pSSCI->shader.descriptorSetMapping[i].pDescriptorInfo, sizeof(XGL_DESCRIPTOR_SLOT_INFO)*pShadowShaderCI->shader.descriptorSetMapping[i].descriptorCount);
}
}
else if (XGL_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO == pTrav->sType) {
@@ -575,6 +582,108 @@
layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, NULL, 0, DRAWSTATE_NONE, "DS", pipeStr);
}
}
+// Dump subgraph w/ DS info
+static void dsDumpDot(FILE* pOutFile)
+{
+ const int i = 0; // hard-coding to just the first DS index for now
+ uint32_t skipUnusedCount = 0; // track consecutive unused slots for minimal reporting
+ DS_LL_HEAD *pDS = getDS(lastBoundDS[i]);
+ XGL_UINT slotOffset = lastBoundSlotOffset[i];
+ if (pDS) {
+ fprintf(pOutFile, "subgraph DS_SLOTS\n{\nlabel=\"DS0 Slots\"\n");
+ // First create simple array node as central DS reference point
+ fprintf(pOutFile, "\"DS0_MEMORY\" [\nlabel = <<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\"> <TR><TD PORT=\"ds2\">DS0 Memory</TD></TR>");
+ uint32_t j;
+ char label[1024];
+ for (j = 0; j < pDS->numSlots; j++) {
+ fprintf(pOutFile, "<TR><TD PORT=\"slot%u\">slot%u</TD></TR>", j, j);
+ }
+ fprintf(pOutFile, "</TABLE>>\n];\n");
+ // Now tie each slot to its info
+ for (j = 0; j < pDS->numSlots; j++) {
+ switch (pDS->dsSlot[j].activeMapping)
+ {
+ case MAPPING_MEMORY:
+ /*
+ if (0 != skipUnusedCount) {// finish sequence of unused slots
+ sprintf(tmp_str, "----Skipped %u slot%s w/o a view attached...\n", skipUnusedCount, (1 != skipUnusedCount) ? "s" : "");
+ strcat(ds_config_str, tmp_str);
+ skipUnusedCount = 0;
+ }*/
+ sprintf(label, "MemAttachInfo Slot%u", j);
+ fprintf(pOutFile, "%s", xgl_gv_print_xgl_memory_view_attach_info(&pDS->dsSlot[j].memView, label));
+ fprintf(pOutFile, "\"DS0_MEMORY\":slot%u -> \"%s\" [];\n", j, label);
+ break;
+ case MAPPING_IMAGE:
+ /*if (0 != skipUnusedCount) {// finish sequence of unused slots
+ sprintf(tmp_str, "----Skipped %u slot%s w/o a view attached...\n", skipUnusedCount, (1 != skipUnusedCount) ? "s" : "");
+ strcat(ds_config_str, tmp_str);
+ skipUnusedCount = 0;
+ }*/
+ sprintf(label, "ImageAttachInfo Slot%u", j);
+ fprintf(pOutFile, "%s", xgl_gv_print_xgl_image_view_attach_info(&pDS->dsSlot[j].imageView, label));
+ fprintf(pOutFile, "\"DS0_MEMORY\":slot%u -> \"%s\" [];\n", j, label);
+ break;
+ case MAPPING_SAMPLER:
+ /*if (0 != skipUnusedCount) {// finish sequence of unused slots
+ sprintf(tmp_str, "----Skipped %u slot%s w/o a view attached...\n", skipUnusedCount, (1 != skipUnusedCount) ? "s" : "");
+ strcat(ds_config_str, tmp_str);
+ skipUnusedCount = 0;
+ }*/
+ sprintf(label, "ImageAttachInfo Slot%u", j);
+ fprintf(pOutFile, "%s", xgl_gv_print_xgl_sampler_create_info(getSamplerCreateInfo(pDS->dsSlot[j].sampler), label));
+ fprintf(pOutFile, "\"DS0_MEMORY\":slot%u -> \"%s\" [];\n", j, label);
+ break;
+ default:
+ /*if (!skipUnusedCount) {// only report start of unused sequences
+ sprintf(tmp_str, "----Skipping slot(s) w/o a view attached...\n");
+ strcat(ds_config_str, tmp_str);
+ }*/
+ skipUnusedCount++;
+ break;
+ }
+
+ }
+ /*if (0 != skipUnusedCount) {// finish sequence of unused slots
+ sprintf(tmp_str, "----Skipped %u slot%s w/o a view attached...\n", skipUnusedCount, (1 != skipUnusedCount) ? "s" : "");
+ strcat(ds_config_str, tmp_str);
+ skipUnusedCount = 0;
+ }*/
+ fprintf(pOutFile, "}\n");
+ }
+}
+// Dump a GraphViz dot file showing the pipeline
+static void dumpDotFile(char *outFileName)
+{
+ PIPELINE_NODE *pPipeTrav = getPipeline(lastBoundPipeline);
+ if (pPipeTrav) {
+ FILE* pOutFile;
+ pOutFile = fopen(outFileName, "w");
+ fprintf(pOutFile, "digraph g {\ngraph [\nrankdir = \"TB\"\n];\nnode [\nfontsize = \"16\"\nshape = \"plaintext\"\n];\nedge [\n];\n");
+ fprintf(pOutFile, "subgraph PipelineStateObject\n{\nlabel=\"Pipeline State Object\"\n");
+ fprintf(pOutFile, "%s", xgl_gv_print_xgl_graphics_pipeline_create_info(pPipeTrav->pCreateTree, "PSO HEAD"));
+ fprintf(pOutFile, "}\n");
+ // TODO : Add dynamic state dump here
+ fprintf(pOutFile, "subgraph dynamicState\n{\nlabel=\"Non-Orthogonal XGL State\"\n");
+ for (uint32_t i = 0; i < XGL_NUM_STATE_BIND_POINT; i++) {
+ if (pLastBoundDynamicState[i]) {
+ switch (pLastBoundDynamicState[i]->sType)
+ {
+ case XGL_STATE_BIND_VIEWPORT:
+ fprintf(pOutFile, "%s", xgl_gv_print_xgl_viewport_state_create_info((XGL_VIEWPORT_STATE_CREATE_INFO*)pLastBoundDynamicState[i]->pCreateInfo, "VIEWPORT State"));
+ break;
+ default:
+ fprintf(pOutFile, "%s", dynamic_gv_display(pLastBoundDynamicState[i]->pCreateInfo, string_XGL_STATE_BIND_POINT(pLastBoundDynamicState[i]->sType)));
+ break;
+ }
+ }
+ }
+ fprintf(pOutFile, "}\n"); // close dynamicState subgraph
+ dsDumpDot(pOutFile);
+ fprintf(pOutFile, "}\n"); // close main graph "g"
+ fclose(pOutFile);
+ }
+}
// Synch up currently bound pipeline settings with DS mappings
static void synchDSMapping()
{
@@ -587,7 +696,6 @@
}
else {
// Synch Descriptor Set Mapping
- pthread_mutex_lock(&globalLock);
for (uint32_t i = 0; i < XGL_MAX_DESCRIPTOR_SETS; i++) {
DS_LL_HEAD *pDS;
if (lastBoundDS[i]) {
@@ -639,7 +747,6 @@
free(tmpStr);
}
}
- pthread_mutex_unlock(&globalLock);
}
}
@@ -688,7 +795,6 @@
uint32_t skipUnusedCount = 0; // track consecutive unused slots for minimal reporting
char tmp_str[1024];
char ds_config_str[1024*256] = {0}; // TODO : Currently making this buffer HUGE w/o overrun protection. Need to be smarter, start smaller, and grow as needed.
- pthread_mutex_lock(&globalLock);
for (uint32_t i = 0; i < XGL_MAX_DESCRIPTOR_SETS; i++) {
if (lastBoundDS[i]) {
DS_LL_HEAD *pDS = getDS(lastBoundDS[i]);
@@ -756,7 +862,6 @@
}
}
}
- pthread_mutex_unlock(&globalLock);
layerCbMsg(XGL_DBG_MSG_UNKNOWN, XGL_VALIDATION_LEVEL_0, NULL, 0, DRAWSTATE_NONE, "DS", ds_config_str);
}
@@ -766,6 +871,11 @@
printDSConfig();
printPipeline();
printDynamicState();
+ static int autoDumpOnce = 1;
+ if (autoDumpOnce) {
+ autoDumpOnce = 0;
+ dumpDotFile("pipeline_dump.dot");
+ }
}
static void initLayerTable()
@@ -1919,6 +2029,11 @@
return result;
}
+XGL_VOID drawStateDumpDotFile(char* outFileName)
+{
+ dumpDotFile(outFileName);
+}
+
XGL_LAYER_EXPORT XGL_VOID* XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const XGL_CHAR* funcName)
{
XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu;
@@ -1951,6 +2066,8 @@
return xglQueueWaitIdle;
else if (!strncmp("xglDeviceWaitIdle", (const char *) funcName, sizeof("xglDeviceWaitIdle")))
return xglDeviceWaitIdle;
+ else if (!strncmp("drawStateDumpDotFile", (const char *) funcName, sizeof("drawStateDumpDotFile")))
+ return drawStateDumpDotFile;
else if (!strncmp("xglGetMemoryHeapCount", (const char *) funcName, sizeof("xglGetMemoryHeapCount")))
return xglGetMemoryHeapCount;
else if (!strncmp("xglGetMemoryHeapInfo", (const char *) funcName, sizeof("xglGetMemoryHeapInfo")))
diff --git a/layers/draw_state.h b/layers/draw_state.h
index 950107c..d505c46 100644
--- a/layers/draw_state.h
+++ b/layers/draw_state.h
@@ -56,3 +56,8 @@
DRAW_END_RANGE = DRAW_INDEXED_INDIRECT,
NUM_DRAW_TYPES = (DRAW_END_RANGE - DRAW_BEGIN_RANGE + 1),
} DRAW_TYPE;
+
+//prototypes for extension functions
+XGL_VOID drawStateDumpDotFile(char* outFileName);
+// Func ptr typedef
+typedef XGL_VOID (*DRAW_STATE_DUMP_DOT_FILE)(char*);
diff --git a/xgl-helper.py b/xgl-helper.py
index d570580..cff1283 100755
--- a/xgl-helper.py
+++ b/xgl-helper.py
@@ -483,6 +483,7 @@
# We do two passes, first pass just generates prototypes for all the functsions
for s in self.struct_dict:
sh_funcs.append('char* %s(const %s* pStruct, const char* prefix);\n' % (self._get_sh_func_name(s), typedef_fwd_dict[s]))
+ sh_funcs.append('\n')
for s in self.struct_dict:
p_out = ""
p_args = ""
@@ -780,6 +781,7 @@
class CMakeGen:
def __init__(self, struct_wrapper=None, out_dir=None):
self.sw = struct_wrapper
+ self.include_headers = []
self.add_lib_file_list = self.sw.get_file_list()
self.out_dir = out_dir
self.out_file = os.path.join(self.out_dir, "CMakeLists.txt")
@@ -801,35 +803,255 @@
return "\n".join(body)
class GraphVizGen:
- def __init__(self, struct_dict=None):
- self.struc_dict = struct_dict
- self.out_file = os.path.join(os.getcwd(), "struct_gv.dot")
+ def __init__(self, struct_dict, prefix, out_dir):
+ self.struct_dict = struct_dict
+ self.api = prefix
+ self.out_file = os.path.join(out_dir, self.api+"_struct_graphviz_helper.h")
self.gvg = CommonFileGen(self.out_file)
-
+
def generate(self):
+ self.gvg.setCopyright("//This is the copyright\n")
self.gvg.setHeader(self._generateHeader())
self.gvg.setBody(self._generateBody())
- self.gvg.setFooter('}')
+ #self.gvg.setFooter('}')
self.gvg.generate()
-
+
+ def set_include_headers(self, include_headers):
+ self.include_headers = include_headers
+
def _generateHeader(self):
- hdr = []
- hdr.append('digraph g {\ngraph [\nrankdir = "LR"\n];')
- hdr.append('node [\nfontsize = "16"\nshape = "plaintext"\n];')
- hdr.append('edge [\n];\n')
- return "\n".join(hdr)
-
+ header = []
+ header.append("//#includes, #defines, globals and such...\n")
+ for f in self.include_headers:
+ if 'xgl_enum_string_helper' not in f:
+ header.append("#include <%s>\n" % f)
+ #header.append('#include "xgl_enum_string_helper.h"\n\n// Function Prototypes\n')
+ header.append("\nchar* dynamic_gv_display(const XGL_VOID* pStruct, const char* prefix);\n")
+ return "".join(header)
+
+ def _get_gv_func_name(self, struct):
+ return "%s_gv_print_%s" % (self.api, struct.lower().strip("_"))
+
+ # Return elements to create formatted string for given struct member
+ def _get_struct_gv_print_formatted(self, struct_member, pre_var_name="", postfix = "\\n", struct_var_name="pStruct", struct_ptr=True, print_array=False, port_label=""):
+ struct_op = "->"
+ pre_var_name = '"%s "' % struct_member['full_type']
+ if not struct_ptr:
+ struct_op = "."
+ member_name = struct_member['name']
+ print_type = "p"
+ cast_type = ""
+ member_post = ""
+ array_index = ""
+ member_print_post = ""
+ if struct_member['array'] and 'CHAR' in struct_member['type']: # just print char array as string
+ print_type = "s"
+ print_array = False
+ elif struct_member['array'] and not print_array:
+ # Just print base address of array when not full print_array
+ cast_type = "(void*)"
+ elif is_type(struct_member['type'], 'enum'):
+ cast_type = "string_%s" % struct_member['type']
+ print_type = "s"
+ elif is_type(struct_member['type'], 'struct'): # print struct address for now
+ cast_type = "(void*)"
+ if not struct_member['ptr']:
+ cast_type = "(void*)&"
+ elif 'BOOL' in struct_member['type']:
+ print_type = "s"
+ member_post = ' ? "TRUE" : "FALSE"'
+ elif 'FLOAT' in struct_member['type']:
+ print_type = "f"
+ elif 'UINT64' in struct_member['type']:
+ print_type = "lu"
+ elif 'UINT8' in struct_member['type']:
+ print_type = "hu"
+ elif True in [ui_str in struct_member['type'] for ui_str in ['UINT', '_SIZE', '_FLAGS', '_SAMPLE_MASK']]:
+ print_type = "u"
+ elif 'INT' in struct_member['type']:
+ print_type = "i"
+ elif struct_member['ptr']:
+ pass
+ else:
+ #print("Unhandled struct type: %s" % struct_member['type'])
+ cast_type = "(void*)"
+ if print_array and struct_member['array']:
+ member_print_post = "[%u]"
+ array_index = " i,"
+ member_post = "[i]"
+ print_out = "<TR><TD>%%s%s%s</TD><TD%s>%%%s%s</TD></TR>" % (member_name, member_print_post, port_label, print_type, postfix) # section of print that goes inside of quotes
+ print_arg = ", %s,%s %s(%s%s%s)%s" % (pre_var_name, array_index, cast_type, struct_var_name, struct_op, member_name, member_post) # section of print passed to portion in quotes
+ return (print_out, print_arg)
+
def _generateBody(self):
- body = []
- for s in self.struc_dict:
- field_num = 1
- body.append('"%s" [\nlabel = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> <TR><TD COLSPAN="2" PORT="f0">%s</TD></TR>' % (s, typedef_fwd_dict[s]))
- for m in sorted(self.struc_dict[s]):
- body.append('<TR><TD PORT="f%i">%s</TD><TD PORT="f%i">%s</TD></TR>' % (field_num, self.struc_dict[s][m]['full_type'], field_num+1, self.struc_dict[s][m]['name']))
- field_num += 2
- body.append('</TABLE>>\n];\n')
- return "".join(body)
-
+ gv_funcs = []
+ array_func_list = [] # structs for which we'll generate an array version of their print function
+ array_func_list.append('xgl_descriptor_slot_info')
+ # For first pass, generate prototype
+ for s in self.struct_dict:
+ gv_funcs.append('char* %s(const %s* pStruct, const char* myNodeName);\n' % (self._get_gv_func_name(s), typedef_fwd_dict[s]))
+ if s.lower().strip("_") in array_func_list:
+ gv_funcs.append('char* %s_array(XGL_UINT count, const %s* pStruct, const char* myNodeName);\n' % (self._get_gv_func_name(s), typedef_fwd_dict[s]))
+ gv_funcs.append('\n')
+ for s in self.struct_dict:
+ p_out = ""
+ p_args = ""
+ stp_list = [] # stp == "struct to print" a list of structs for this API call that should be printed as structs
+ # the fields below are a super-hacky way for now to get port labels into GV output, TODO : Clean this up!
+ pl_dict = {}
+ struct_num = 0
+ # This isn't great but this pre-pass counts chars in struct members and flags structs w/ pNext
+ for m in sorted(self.struct_dict[s]):
+ if 'pNext' == self.struct_dict[s][m]['name'] or is_type(self.struct_dict[s][m]['type'], 'struct'):
+ stp_list.append(self.struct_dict[s][m])
+ if 'pNext' == self.struct_dict[s][m]['name']:
+ pl_dict[m] = ' PORT=\\"pNext\\"'
+ else:
+ pl_dict[m] = ' PORT=\\"struct%i\\"' % struct_num
+ struct_num += 1
+ gv_funcs.append('char* %s(const %s* pStruct, const char* myNodeName)\n{\n char* str;\n' % (self._get_gv_func_name(s), typedef_fwd_dict[s]))
+ num_stps = len(stp_list);
+ total_strlen_str = ''
+ if 0 != num_stps:
+ gv_funcs.append(" char* tmpStr;\n")
+ gv_funcs.append(" char nodeName[100];\n")
+ gv_funcs.append(" char dummy_char = '\\0';\n")
+ gv_funcs.append(' char* stp_strs[%i];\n' % num_stps)
+ for index in range(num_stps):
+ if (stp_list[index]['ptr']):
+ if 'pDescriptorInfo' == stp_list[index]['name']:
+ gv_funcs.append(' if (pStruct->pDescriptorInfo && (0 != pStruct->descriptorCount)) {\n')
+ else:
+ gv_funcs.append(' if (pStruct->%s) {\n' % stp_list[index]['name'])
+ if 'pNext' == stp_list[index]['name']:
+ gv_funcs.append(' sprintf(nodeName, "pNext_%p", (void*)pStruct->pNext);\n')
+ gv_funcs.append(' tmpStr = dynamic_gv_display((XGL_VOID*)pStruct->pNext, nodeName);\n')
+ gv_funcs.append(' stp_strs[%i] = (char*)malloc(256+strlen(tmpStr)+strlen(nodeName)+strlen(myNodeName));\n' % index)
+ gv_funcs.append(' sprintf(stp_strs[%i], "%%s\\n\\"%%s\\":pNext -> \\"%%s\\" [];\\n", tmpStr, myNodeName, nodeName);\n' % index)
+ gv_funcs.append(' free(tmpStr);\n')
+ else:
+ gv_funcs.append(' sprintf(nodeName, "%s_%%p", (void*)pStruct->%s);\n' % (stp_list[index]['name'], stp_list[index]['name']))
+ if 'pDescriptorInfo' == stp_list[index]['name']:
+ gv_funcs.append(' tmpStr = %s_array(pStruct->descriptorCount, pStruct->%s, nodeName);\n' % (self._get_gv_func_name(stp_list[index]['type']), stp_list[index]['name']))
+ else:
+ gv_funcs.append(' tmpStr = %s(pStruct->%s, nodeName);\n' % (self._get_gv_func_name(stp_list[index]['type']), stp_list[index]['name']))
+ gv_funcs.append(' stp_strs[%i] = (char*)malloc(256+strlen(tmpStr)+strlen(nodeName)+strlen(myNodeName));\n' % (index))
+ gv_funcs.append(' sprintf(stp_strs[%i], "%%s\\n\\"%%s\\":struct%i -> \\"%%s\\" [];\\n", tmpStr, myNodeName, nodeName);\n' % (index, index))
+ gv_funcs.append(' }\n')
+ gv_funcs.append(" else\n stp_strs[%i] = &dummy_char;\n" % (index))
+ elif stp_list[index]['array']: # TODO : For now just printing first element of array
+ gv_funcs.append(' sprintf(nodeName, "%s_%%p", (void*)&pStruct->%s[0]);\n' % (stp_list[index]['name'], stp_list[index]['name']))
+ gv_funcs.append(' tmpStr = %s(&pStruct->%s[0], nodeName);\n' % (self._get_gv_func_name(stp_list[index]['type']), stp_list[index]['name']))
+ gv_funcs.append(' stp_strs[%i] = (char*)malloc(256+strlen(tmpStr)+strlen(nodeName)+strlen(myNodeName));\n' % (index))
+ gv_funcs.append(' sprintf(stp_strs[%i], "%%s\\n\\"%%s\\":struct%i -> \\"%%s\\" [];\\n", tmpStr, myNodeName, nodeName);\n' % (index, index))
+ else:
+ gv_funcs.append(' sprintf(nodeName, "%s_%%p", (void*)&pStruct->%s);\n' % (stp_list[index]['name'], stp_list[index]['name']))
+ gv_funcs.append(' tmpStr = %s(&pStruct->%s, nodeName);\n' % (self._get_gv_func_name(stp_list[index]['type']), stp_list[index]['name']))
+ gv_funcs.append(' stp_strs[%i] = (char*)malloc(256+strlen(tmpStr)+strlen(nodeName)+strlen(myNodeName));\n' % (index))
+ gv_funcs.append(' sprintf(stp_strs[%i], "%%s\\n\\"%%s\\":struct%i -> \\"%%s\\" [];\\n", tmpStr, myNodeName, nodeName);\n' % (index, index))
+ total_strlen_str += 'strlen(stp_strs[%i]) + ' % index
+ gv_funcs.append(' str = (char*)malloc(%ssizeof(char)*2048);\n' % (total_strlen_str))
+ gv_funcs.append(' sprintf(str, "\\"%s\\" [\\nlabel = <<TABLE BORDER=\\"0\\" CELLBORDER=\\"1\\" CELLSPACING=\\"0\\"><TR><TD COLSPAN=\\"2\\">%s (%p)</TD></TR>')
+ p_args = ", myNodeName, myNodeName, pStruct"
+ for m in sorted(self.struct_dict[s]):
+ plabel = ""
+ if m in pl_dict:
+ plabel = pl_dict[m]
+ (p_out1, p_args1) = self._get_struct_gv_print_formatted(self.struct_dict[s][m], port_label=plabel)
+ p_out += p_out1
+ p_args += p_args1
+ p_out += '</TABLE>>\\n];\\n\\n"'
+ p_args += ");\n"
+ gv_funcs.append(p_out)
+ gv_funcs.append(p_args)
+ if 0 != num_stps:
+ gv_funcs.append(' for (int32_t stp_index = %i; stp_index >= 0; stp_index--) {\n' % (num_stps-1))
+ gv_funcs.append(' if (0 < strlen(stp_strs[stp_index])) {\n')
+ gv_funcs.append(' strncat(str, stp_strs[stp_index], strlen(stp_strs[stp_index]));\n')
+ gv_funcs.append(' free(stp_strs[stp_index]);\n')
+ gv_funcs.append(' }\n')
+ gv_funcs.append(' }\n')
+ gv_funcs.append(" return str;\n}\n")
+ if s.lower().strip("_") in array_func_list:
+ gv_funcs.append('char* %s_array(XGL_UINT count, const %s* pStruct, const char* myNodeName)\n{\n char* str;\n char tmpStr[1024];\n' % (self._get_gv_func_name(s), typedef_fwd_dict[s]))
+ gv_funcs.append(' str = (char*)malloc(sizeof(char)*1024*count);\n')
+ gv_funcs.append(' sprintf(str, "\\"%s\\" [\\nlabel = <<TABLE BORDER=\\"0\\" CELLBORDER=\\"1\\" CELLSPACING=\\"0\\"><TR><TD COLSPAN=\\"3\\">%s (%p)</TD></TR>", myNodeName, myNodeName, pStruct);\n')
+ gv_funcs.append(' for (uint32_t i=0; i < count; i++) {\n')
+ gv_funcs.append(' sprintf(tmpStr, "');
+ p_args = ""
+ p_out = ""
+ for m in sorted(self.struct_dict[s]):
+ if 2 == m: # TODO : Hard-coded hack to skip last element of union for xgl_descriptor_slot_info struct
+ continue
+ plabel = ""
+ (p_out1, p_args1) = self._get_struct_gv_print_formatted(self.struct_dict[s][m], port_label=plabel)
+ if 0 == m: # Add array index notation at end of first row (TODO : ROWSPAN# should be dynamic based on number of elements, but hard-coding for now)
+ p_out1 = '%s<TD ROWSPAN=\\"2\\" PORT=\\"slot%%u\\">%%u</TD></TR>' % (p_out1[:-5])
+ p_args1 += ', i, i'
+ p_out += p_out1
+ p_args += p_args1
+ p_out += '"'
+ p_args += ");\n"
+ p_args = p_args.replace('->', '[i].')
+ gv_funcs.append(p_out);
+ gv_funcs.append(p_args);
+ gv_funcs.append(' strncat(str, tmpStr, strlen(tmpStr));\n')
+ gv_funcs.append(' }\n')
+ gv_funcs.append(' strncat(str, "</TABLE>>\\n];\\n\\n", 20);\n')
+ # TODO : Another hard-coded hack. Tie these slots to "magical" DS0_MEMORY slots that should appear separately
+ gv_funcs.append(' for (uint32_t i=0; i < count; i++) {\n')
+ gv_funcs.append(' sprintf(tmpStr, "\\"%s\\":slot%u -> \\"DS0_MEMORY\\":slot%u [];\\n", myNodeName, i, i);\n')
+ gv_funcs.append(' strncat(str, tmpStr, strlen(tmpStr));\n')
+ gv_funcs.append(' }\n')
+ gv_funcs.append(' return str;\n}\n')
+ # Add function to dynamically print out unknown struct
+ gv_funcs.append("char* dynamic_gv_display(const XGL_VOID* pStruct, const char* nodeName)\n{\n")
+ gv_funcs.append(" // Cast to APP_INFO ptr initially just to pull sType off struct\n")
+ gv_funcs.append(" XGL_STRUCTURE_TYPE sType = ((XGL_APPLICATION_INFO*)pStruct)->sType;\n")
+ gv_funcs.append(" switch (sType)\n {\n")
+ for e in enum_type_dict:
+ if "_STRUCTURE_TYPE" in e:
+ for v in sorted(enum_type_dict[e]):
+ struct_name = v.replace("_STRUCTURE_TYPE", "")
+ print_func_name = self._get_gv_func_name(struct_name)
+ # TODO : Hand-coded fixes for some exceptions
+ if 'XGL_PIPELINE_CB_STATE_CREATE_INFO' in struct_name:
+ struct_name = 'XGL_PIPELINE_CB_STATE'
+ elif 'XGL_SEMAPHORE_CREATE_INFO' in struct_name:
+ struct_name = 'XGL_QUEUE_SEMAPHORE_CREATE_INFO'
+ print_func_name = self._get_gv_func_name(struct_name)
+ elif 'XGL_SEMAPHORE_OPEN_INFO' in struct_name:
+ struct_name = 'XGL_QUEUE_SEMAPHORE_OPEN_INFO'
+ print_func_name = self._get_gv_func_name(struct_name)
+ gv_funcs.append(' case %s:\n' % (v))
+ gv_funcs.append(' return %s((%s*)pStruct, nodeName);\n' % (print_func_name, struct_name))
+ #gv_funcs.append(' }\n')
+ #gv_funcs.append(' break;\n')
+ gv_funcs.append(" }\n")
+ gv_funcs.append("}")
+ return "".join(gv_funcs)
+
+
+
+
+
+# def _generateHeader(self):
+# hdr = []
+# hdr.append('digraph g {\ngraph [\nrankdir = "LR"\n];')
+# hdr.append('node [\nfontsize = "16"\nshape = "plaintext"\n];')
+# hdr.append('edge [\n];\n')
+# return "\n".join(hdr)
+#
+# def _generateBody(self):
+# body = []
+# for s in self.struc_dict:
+# field_num = 1
+# body.append('"%s" [\nlabel = <<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> <TR><TD COLSPAN="2" PORT="f0">%s</TD></TR>' % (s, typedef_fwd_dict[s]))
+# for m in sorted(self.struc_dict[s]):
+# body.append('<TR><TD PORT="f%i">%s</TD><TD PORT="f%i">%s</TD></TR>' % (field_num, self.struc_dict[s][m]['full_type'], field_num+1, self.struc_dict[s][m]['name']))
+# field_num += 2
+# body.append('</TABLE>>\n];\n')
+# return "".join(body)
def main(argv=None):
opts = handle_args()
@@ -883,7 +1105,8 @@
cmg = CMakeGen(sw, os.path.dirname(enum_filename))
cmg.generate()
if opts.gen_graphviz:
- gv = GraphVizGen(struct_dict)
+ gv = GraphVizGen(struct_dict, os.path.basename(opts.input_file).strip(".h"), os.path.dirname(enum_filename))
+ gv.set_include_headers([os.path.basename(opts.input_file),os.path.basename(enum_filename),"stdint.h","stdio.h","stdlib.h"])
gv.generate()
print("DONE!")
#print(typedef_rev_dict)
@@ -892,83 +1115,3 @@
if __name__ == "__main__":
sys.exit(main())
-
-
-## Example class for GR_APPLICATION_INFO struct
-##include <mantle.h>
-#
-#class gr_application_info_struct_wrapper {
-#public:
-# // Constructors
-# gr_application_info_struct_wrapper();
-# gr_application_info_struct_wrapper(GR_APPLICATION_INFO* pInStruct);
-# // Destructor
-# virtual ~gr_application_info_struct_wrapper();
-#
-# void display_txt()
-# // get functions
-# // set functions for every non-const struct member
-#
-#private:
-# GR_APPLICATION_INFO m_struct;
-#};
-#
-#gr_application_info_struct_wrapper::gr_application_info_struct_wrapper() : m_struct() {}
-#
-#// Output struct address on single line
-#gr_application_info_struct_wrapper::display_single_txt()
-#{
-# printf(" GR_APPLICATION_INFO = %p", &m_struct);
-#}
-#// Output struct in txt format
-#gr_application_info_struct_wrapper::display_txt()
-#{
-# printf("GR_APPLICATION_INFO struct contents:\n");
-# printf(" pAppName: %s\n", m_struct.pAppName);
-# printf(" appVersion: %i\n", m_struct.appVersion);
-# printf(" pEngineNmae: %s\n", m_struct.pEngineName);
-# printf(" engineVersion: %i\n", m_struct.engineVersion);
-# printf(" apiVersion: %i\n", m_struct.apiVersion);
-#}
-#// Output struct including detailed info on pointed-to structs
-#gr_application_info_struct_wrapper::display_full_txt()
-#{
-#
-# printf("%*s%GR_APPLICATION_INFO struct contents:\n", indent, "");
-# printf(" pAppName: %s\n", m_struct.pAppName);
-# printf(" appVersion: %i\n", m_struct.appVersion);
-# printf(" pEngineNmae: %s\n", m_struct.pEngineName);
-# printf(" engineVersion: %i\n", m_struct.engineVersion);
-# printf(" apiVersion: %i\n", m_struct.apiVersion);
-#}
-
-
-# Example of helper function to pretty-print enum info
-#static const char* string_GR_RESULT_CODE(GR_RESULT result)
-#{
-# switch ((GR_RESULT_CODE)result)
-# {
-# // Return codes for successful operation execution
-# case GR_SUCCESS:
-# return "GR_SUCCESS";
-# case GR_UNSUPPORTED:
-# return "GR_UNSUPPORTED";
-# case GR_NOT_READY:
-# return "GR_NOT_READY";
-# case GR_TIMEOUT:
-# return "GR_TIMEOUT";
-# }
-# return "Unhandled GR_RESULT_CODE";
-#}
-
-# Dynamic print function
-# void dynamic_display_full_txt(XGL_STRUCTURE_TYPE sType, void* pStruct, uint32_t indent)
-# {
-# switch (sType)
-# {
-# case XGL_STRUCTURE_TYPE_COLOR_BLEND_STATE_CREATE_INFO:
-# xgl_color_blend_state_create_info_struct_wrapper swc((XGL_COLOR_BLEND_STATE_CREATE_INFO*)pStruct);
-# swc.set_indent(indent);
-# swc.display_full_txt();
-# }
-# }