layers: Create APIDump[NoAddr]Cpp layers using c++ string and streams
authorTobin Ehlis <tobin@lunarg.com>
Sat, 10 Jan 2015 19:42:41 +0000 (12:42 -0700)
committerCourtney Goeltzenleuchter <courtney@LunarG.com>
Thu, 5 Feb 2015 00:58:05 +0000 (17:58 -0700)
This is fully functional version of APIDump & APIDumpNoAddr using std::string and i/o streams
Hopefully this will fix a few random crashes that were being hit with rendersystemtests & APIDump
Long term we won't keep generating so many different APIDump layers.
The main APIDump layer will be the Cpp version and it will have settings file options to vary file i/o and noaddr along with any new options.
We should keep the C version of APIDump around until we're sure we don't need it, though.

layers/CMakeLists.txt
xgl-helper.py
xgl-layer-generate.py

index 7a4a752..b733742 100644 (file)
@@ -37,7 +37,9 @@ add_custom_command(OUTPUT xgl_generic_intercept_proc_helper.h
 run_xgl_helper(gen_enum_string_helper xgl_enum_string_helper.h)
 run_xgl_helper(gen_struct_wrappers
        xgl_struct_string_helper.h
+        xgl_struct_string_helper_cpp.h
        xgl_struct_string_helper_no_addr.h
+       xgl_struct_string_helper_no_addr_cpp.h
        xgl_struct_wrappers.h
        xgl_struct_wrappers.cpp
 )
@@ -49,6 +51,8 @@ add_custom_target(generate_xgl_layer_helpers DEPENDS
        xgl_enum_string_helper.h
        xgl_struct_string_helper.h
        xgl_struct_string_helper_no_addr.h
+        xgl_struct_string_helper_cpp.h
+       xgl_struct_string_helper_no_addr_cpp.h
        xgl_struct_wrappers.h
        xgl_struct_wrappers.cpp
        xgl_struct_graphviz_helper.h
@@ -58,6 +62,8 @@ run_xgl_layer_generate(Generic generic_layer.c)
 run_xgl_layer_generate(ApiDump api_dump.c)
 run_xgl_layer_generate(ApiDumpFile api_dump_file.c)
 run_xgl_layer_generate(ApiDumpNoAddr api_dump_no_addr.c)
+run_xgl_layer_generate(ApiDumpCpp api_dump.cpp)
+run_xgl_layer_generate(ApiDumpNoAddrCpp api_dump_no_addr.cpp)
 run_xgl_layer_generate(ObjectTracker object_track.c)
 
 add_xgl_layer(Basic basic.cpp)
@@ -69,4 +75,6 @@ add_xgl_layer(Generic generic_layer.c)
 add_xgl_layer(APIDump api_dump.c)
 add_xgl_layer(APIDumpFile api_dump_file.c)
 add_xgl_layer(APIDumpNoAddr api_dump_no_addr.c)
+add_xgl_layer(APIDumpCpp api_dump.cpp)
+add_xgl_layer(APIDumpNoAddrCpp api_dump_no_addr.cpp)
 add_xgl_layer(ObjectTracker object_track.c)
index f1622a2..67cada7 100755 (executable)
@@ -319,10 +319,13 @@ class StructWrapperGen:
         self.class_filename = os.path.join(out_dir, self.api+"_struct_wrappers.cpp")
         self.string_helper_filename = os.path.join(out_dir, self.api+"_struct_string_helper.h")
         self.string_helper_no_addr_filename = os.path.join(out_dir, self.api+"_struct_string_helper_no_addr.h")
+        self.string_helper_cpp_filename = os.path.join(out_dir, self.api+"_struct_string_helper_cpp.h")
+        self.string_helper_no_addr_cpp_filename = os.path.join(out_dir, self.api+"_struct_string_helper_no_addr_cpp.h")
         self.no_addr = False
         self.hfg = CommonFileGen(self.header_filename)
         self.cfg = CommonFileGen(self.class_filename)
         self.shg = CommonFileGen(self.string_helper_filename)
+        self.shcppg = CommonFileGen(self.string_helper_cpp_filename)
         #print(self.header_filename)
         self.header_txt = ""
         self.definition_txt = ""
@@ -334,8 +337,10 @@ class StructWrapperGen:
         self.no_addr = no_addr
         if self.no_addr:
             self.shg = CommonFileGen(self.string_helper_no_addr_filename)
+            self.shcppg = CommonFileGen(self.string_helper_no_addr_cpp_filename)
         else:
             self.shg = CommonFileGen(self.string_helper_filename)
+            self.shcppg = CommonFileGen(self.string_helper_cpp_filename)
 
     # Return class name for given struct name
     def get_class_name(self, struct_name):
@@ -369,6 +374,14 @@ class StructWrapperGen:
         self.shg.setBody(self._generateStringHelperFunctions())
         self.shg.generate()
 
+    # Generate cpp-style .h file that contains functions for printing structs
+    def generateStringHelperCpp(self):
+        print("Generating struct string helper cpp")
+        self.shcppg.setCopyright(self._generateCopyright())
+        self.shcppg.setHeader(self._generateStringHelperHeaderCpp())
+        self.shcppg.setBody(self._generateStringHelperFunctionsCpp())
+        self.shcppg.generate()
+
     def _generateCopyright(self):
         return "//This is the copyright\n"
 
@@ -503,11 +516,9 @@ class StructWrapperGen:
             p_args = ""
             stp_list = [] # stp == "struct to print" a list of structs for this API call that should be printed as structs
             # This isn't great but this pre-pass counts chars in struct members and flags structs w/ pNext
-            struct_char_count = 0 # TODO : Use this to vary size of memory allocations for strings?
             for m in 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])
-                struct_char_count += len(self.struct_dict[s][m]['name']) + 32
             sh_funcs.append('char* %s(const %s* pStruct, const char* prefix)\n{\n    char* str;\n' % (self._get_sh_func_name(s), typedef_fwd_dict[s]))
             sh_funcs.append("    size_t len;\n")
             num_stps = len(stp_list);
@@ -526,9 +537,9 @@ class StructWrapperGen:
                             sh_funcs.append('        len = 256+strlen(tmpStr);\n')
                             sh_funcs.append('        stp_strs[%i] = (char*)malloc(len);\n' % index)
                             if self.no_addr:
-                                sh_funcs.append('        snprintf(stp_strs[%i], len, "   %%spNext (addr)\\n%%s", prefix, tmpStr);\n' % index)
+                                sh_funcs.append('        snprintf(stp_strs[%i], len, " %%spNext (addr)\\n%%s", prefix, tmpStr);\n' % index)
                             else:
-                                sh_funcs.append('        snprintf(stp_strs[%i], len, "   %%spNext (%%p)\\n%%s", prefix, (void*)pStruct->pNext, tmpStr);\n' % index)
+                                sh_funcs.append('        snprintf(stp_strs[%i], len, " %%spNext (%%p)\\n%%s", prefix, (void*)pStruct->pNext, tmpStr);\n' % index)
                             sh_funcs.append('        free(tmpStr);\n')
                         else:
                             sh_funcs.append('        tmpStr = %s(pStruct->%s, extra_indent);\n' % (self._get_sh_func_name(stp_list[index]['type']), stp_list[index]['name']))
@@ -605,7 +616,139 @@ class StructWrapperGen:
                 sh_funcs.append("    }\n")
         sh_funcs.append("}")
         return "".join(sh_funcs)
-                
+
+    def _generateStringHelperFunctionsCpp(self):
+        # declare str & tmp str
+        # declare array of stringstreams for every struct ptr in current struct
+        # declare array of stringstreams for every non-string element in current struct
+        # For every struct ptr, it non-Null, then set it's string, else set to NULL str
+        # For every non-string element, set it's string stream
+        # create and return final string
+        sh_funcs = []
+        # First generate prototypes for every struct
+        for s in self.struct_dict:
+            sh_funcs.append('string %s(const %s* pStruct, const string prefix);' % (self._get_sh_func_name(s), typedef_fwd_dict[s]))
+        sh_funcs.append('\n')
+        for s in self.struct_dict:
+            num_non_enum_elems = [is_type(self.struct_dict[s][elem]['type'], 'enum') for elem in self.struct_dict[s]].count(False)
+            stp_list = [] # stp == "struct to print" a list of structs for this API call that should be printed as structs
+            # This isn't great but this pre-pass counts chars in struct members and flags structs w/ pNext
+            for m in 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])
+            sh_funcs.append('string %s(const %s* pStruct, const string prefix)\n{' % (self._get_sh_func_name(s), typedef_fwd_dict[s]))
+            sh_funcs.append('    string final_str;')
+            sh_funcs.append('    string tmp_str;')
+            sh_funcs.append('    string extra_indent = "  " + prefix;')
+            sh_funcs.append('    stringstream ss[%u];' % num_non_enum_elems)
+            num_stps = len(stp_list)
+            # First generate code for any embedded structs
+            if 0 < num_stps:
+                sh_funcs.append('    string stp_strs[%u];' % num_stps)
+                idx_ss_decl = False # Make sure to only decl this once
+                for index in range(num_stps):
+                    addr_char = '&'
+                    if stp_list[index]['ptr']:
+                        addr_char = ''
+                    if (stp_list[index]['ptr']):
+                        sh_funcs.append('    if (pStruct->%s) {' % stp_list[index]['name'])
+                        if 'pNext' == stp_list[index]['name']:
+                            sh_funcs.append('        tmp_str = dynamic_display((XGL_VOID*)pStruct->pNext, prefix);')
+                        else:
+                            sh_funcs.append('        tmp_str = %s(pStruct->%s, extra_indent);' % (self._get_sh_func_name(stp_list[index]['type']), stp_list[index]['name']))
+                        sh_funcs.append('        ss[%u] << %spStruct->%s;' % (index, addr_char, stp_list[index]['name']))
+                        if self.no_addr:
+                            sh_funcs.append('        stp_strs[%u] = " " + prefix + "%s (addr)\\n" + tmp_str;' % (index, stp_list[index]['name']))
+                        else:
+                            sh_funcs.append('        stp_strs[%u] = " " + prefix + "%s (" + ss[%u].str() + ")\\n" + tmp_str;' % (index, stp_list[index]['name'], index))
+                        sh_funcs.append('        ss[%u].str("");' % (index))
+                        sh_funcs.append('    }')
+                        sh_funcs.append('    else')
+                        sh_funcs.append('        stp_strs[%u] = "";' % index)
+                    elif (stp_list[index]['array']):
+                        sh_funcs.append('    stp_strs[%u] = "";' % index)
+                        if not idx_ss_decl:
+                            sh_funcs.append('    stringstream index_ss;')
+                            idx_ss_decl = True
+                        sh_funcs.append('    for (uint32_t i = 0; i < %s; i++) {' % stp_list[index]['array_size'])
+                        sh_funcs.append('        index_ss.str("");')
+                        sh_funcs.append('        index_ss << i;')
+                        sh_funcs.append('        ss[%u] << %spStruct->%s[i];' % (index, addr_char, stp_list[index]['name']))
+                        sh_funcs.append('        tmp_str = %s(&pStruct->%s[i], extra_indent);' % (self._get_sh_func_name(stp_list[index]['type']), stp_list[index]['name']))
+                        if self.no_addr:
+                            sh_funcs.append('        stp_strs[%u] += " " + prefix + "%s[" + index_ss.str() + "] (addr)\\n" + tmp_str;' % (index, stp_list[index]['name']))
+                        else:
+                            sh_funcs.append('        stp_strs[%u] += " " + prefix + "%s[" + index_ss.str() + "] (" + ss[%u].str() + ")\\n" + tmp_str;' % (index, stp_list[index]['name'], index))
+                        sh_funcs.append('        ss[%u].str("");' % index)
+                        sh_funcs.append('    }')
+                    else:
+                        sh_funcs.append('    tmp_str = %s(&pStruct->%s, extra_indent);' % (self._get_sh_func_name(stp_list[index]['type']), stp_list[index]['name']))
+                        sh_funcs.append('    ss[%u] << %spStruct->%s;' % (index, addr_char, stp_list[index]['name']))
+                        if self.no_addr:
+                            sh_funcs.append('    stp_strs[%u] = " " + prefix + "%s (addr)\\n" + tmp_str;' % (index, stp_list[index]['name']))
+                        else:
+                            sh_funcs.append('    stp_strs[%u] = " " + prefix + "%s (" + ss[%u].str() + ")\\n" + tmp_str;' % (index, stp_list[index]['name'], index))
+                        sh_funcs.append('    ss[%u].str("");' % index)
+            # Now print non-enum data members
+            index = 0
+            final_str = ''
+            for m in sorted(self.struct_dict[s]):
+                if not is_type(self.struct_dict[s][m]['type'], 'enum'):
+                    if is_type(self.struct_dict[s][m]['type'], 'struct') and not self.struct_dict[s][m]['ptr']:
+                        if self.no_addr:
+                            sh_funcs.append('    ss[%u].str("addr");' % (index))
+                        else:
+                            sh_funcs.append('    ss[%u] << &pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
+                    elif 'BOOL' in self.struct_dict[s][m]['type']:
+                        sh_funcs.append('    ss[%u].str(pStruct->%s ? "TRUE" : "FALSE");' % (index, self.struct_dict[s][m]['name']))
+                    elif 'UINT8' in self.struct_dict[s][m]['type']:
+                        sh_funcs.append('    ss[%u] << (uint32_t)pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
+                    else:
+                        (po, pa) = self._get_struct_print_formatted(self.struct_dict[s][m])
+                        if "addr" in po or self.struct_dict[s][m]['ptr']:
+                            sh_funcs.append('    ss[%u].str("addr");' % (index))
+                        else:
+                            sh_funcs.append('    ss[%u] << pStruct->%s;' % (index, self.struct_dict[s][m]['name']))
+                    value_print = 'ss[%u].str()' % index
+                    index += 1
+                else:
+                    value_print = 'string_%s(pStruct->%s)' % (self.struct_dict[s][m]['type'], self.struct_dict[s][m]['name'])
+                final_str += ' + prefix + "%s = " + %s + "\\n"' % (self.struct_dict[s][m]['name'], value_print)
+            final_str = final_str[3:] # strip off the initial ' + '
+            if 0 != num_stps:
+                final_str += " + %s" % " + ".join(['stp_strs[%u]' % n for n in reversed(range(num_stps))])
+            sh_funcs.append('    final_str = %s;' % final_str)
+            sh_funcs.append('    return final_str;\n}')
+        # Add function to dynamically print out unknown struct
+        sh_funcs.append("string dynamic_display(const XGL_VOID* pStruct, const string prefix)\n{")
+        sh_funcs.append("    // Cast to APP_INFO ptr initially just to pull sType off struct")
+        sh_funcs.append("    XGL_STRUCTURE_TYPE sType = ((XGL_APPLICATION_INFO*)pStruct)->sType;")
+        sh_funcs.append('    string indent = "    ";')
+        sh_funcs.append('    indent += prefix;')
+        sh_funcs.append("    switch (sType)\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_sh_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_sh_func_name(struct_name)
+                    elif 'XGL_SEMAPHORE_OPEN_INFO' in struct_name:
+                        struct_name = 'XGL_QUEUE_SEMAPHORE_OPEN_INFO'
+                        print_func_name = self._get_sh_func_name(struct_name)
+                    sh_funcs.append('        case %s:\n        {' % (v))
+                    sh_funcs.append('            return %s((%s*)pStruct, indent);' % (print_func_name, struct_name))
+                    sh_funcs.append('        }')
+                    sh_funcs.append('        break;')
+                sh_funcs.append("        default:")
+                sh_funcs.append("        return NULL;")
+                sh_funcs.append("    }")
+        sh_funcs.append("}")
+        return "\n".join(sh_funcs)
         
     def _genStructMemberPrint(self, member, s, array, struct_array):
         (p_out, p_arg) = self._get_struct_print_formatted(self.struct_dict[s][member], pre_var_name="&m_dummy_prefix", struct_var_name="m_struct", struct_ptr=False, print_array=True)
@@ -708,7 +851,18 @@ class StructWrapperGen:
         header.append('#include "xgl_enum_string_helper.h"\n\n// Function Prototypes\n')
         header.append("char* dynamic_display(const XGL_VOID* pStruct, const char* prefix);\n")
         return "".join(header)
-        
+
+    def _generateStringHelperHeaderCpp(self):
+        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')
+        header.append('using namespace std;\n\n// Function Prototypes\n')
+        header.append("string dynamic_display(const XGL_VOID* pStruct, const string prefix);\n")
+        return "".join(header)
+
     def _generateHeader(self):
         header = []
         header.append("//#includes, #defines, globals and such...\n")
@@ -1150,6 +1304,11 @@ def main(argv=None):
         # Generate a 2nd helper file that excludes addrs
         sw.set_no_addr(True)
         sw.generateStringHelper()
+        sw.set_no_addr(False)
+        sw.set_include_headers([os.path.basename(opts.input_file),os.path.basename(enum_sh_filename),"stdint.h","stdio.h","stdlib.h","iostream","sstream","string"])
+        sw.generateStringHelperCpp()
+        sw.set_no_addr(True)
+        sw.generateStringHelperCpp()
     if opts.gen_cmake:
         cmg = CMakeGen(sw, os.path.dirname(enum_sh_filename))
         cmg.generate()
index 09ebeee..c261528 100755 (executable)
@@ -93,7 +93,7 @@ class Subcommand(object):
         pass
 
     # Return set of printf '%' qualifier and input to that qualifier
-    def _get_printf_params(self, xgl_type, name, output_param):
+    def _get_printf_params(self, xgl_type, name, output_param, cpp=False):
         # TODO : Need ENUM and STRUCT checks here
         if "_TYPE" in xgl_type: # TODO : This should be generic ENUM check
             return ("%s", "string_%s(%s)" % (xgl_type.strip('const ').strip('*'), name))
@@ -109,19 +109,25 @@ class Subcommand(object):
             return ("%zu", name)
         if "FLOAT" in xgl_type:
             if '[' in xgl_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
+                if cpp:
+                    return ("[%i, %i, %i, %i]", '"[" << %s[0] << "," << %s[1] << "," << %s[2] << "," << %s[3] << "]"' % (name, name, name, name))
                 return ("[%f, %f, %f, %f]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
             return ("%f", name)
         if "BOOL" in xgl_type or 'xcb_randr_crtc_t' in xgl_type:
             return ("%u", name)
         if True in [t in xgl_type for t in ["INT", "FLAGS", "MASK", "xcb_window_t"]]:
             if '[' in xgl_type: # handle array, current hard-coded to 4 (TODO: Make this dynamic)
+                if cpp:
+                    return ("[%i, %i, %i, %i]", "%s[0] << %s[1] << %s[2] << %s[3]" % (name, name, name, name))
                 return ("[%i, %i, %i, %i]", "%s[0], %s[1], %s[2], %s[3]" % (name, name, name, name))
             if '*' in xgl_type:
                 return ("%i", "*(%s)" % name)
             return ("%i", name)
         # TODO : This is special-cased as there's only one "format" param currently and it's nice to expand it
         if "XGL_FORMAT" == xgl_type:
-           return ("{%s.channelFormat = %%s, %s.numericFormat = %%s}" % (name, name), "string_XGL_CHANNEL_FORMAT(%s.channelFormat), string_XGL_NUM_FORMAT(%s.numericFormat)" % (name, name))
+            if cpp:
+                return ("%p", "&%s" % name)
+            return ("{%s.channelFormat = %%s, %s.numericFormat = %%s}" % (name, name), "string_XGL_CHANNEL_FORMAT(%s.channelFormat), string_XGL_NUM_FORMAT(%s.numericFormat)" % (name, name))
         if output_param:
             return ("%p", "(void*)*%s" % name)
         return ("%p", "(void*)(%s)" % name)
@@ -211,6 +217,8 @@ class Subcommand(object):
         layer_name = layer
         if no_addr:
             layer_name = "%sNoAddr" % layer
+            if 'Cpp' in layer_name:
+                layer_name = "APIDumpNoAddrCpp"
         funcs = []
         for proto in self.protos:
             if proto.name != "GetProcAddr" and proto.name != "InitAndEnumerateGpus":
@@ -273,6 +281,117 @@ class Subcommand(object):
                                  '    fflush(stdout);\n'
                                  '%s'
                                  '}' % (qual, decl, proto.params[0].name, proto.name, ret_val, c_call, proto.name, stmt))
+                elif "APIDumpCpp" in layer:
+                    decl = proto.c_func(prefix="xgl", attr="XGLAPI")
+                    param0_name = proto.params[0].name
+                    ret_val = ''
+                    stmt = ''
+                    cis_param_index = [] # Store list of indices when func has struct params
+                    create_params = 0 # Num of params at end of function that are created and returned as output values
+                    if 'WsiX11CreatePresentableImage' in proto.name:
+                        create_params = -2
+                    elif 'Create' in proto.name or 'Alloc' in proto.name or 'MapMemory' in proto.name:
+                        create_params = -1
+                    if proto.ret != "XGL_VOID":
+                        ret_val = "XGL_RESULT result = "
+                        stmt = "    return result;\n"
+                    f_open = ''
+                    f_close = ''
+                    if "File" in layer:
+                        file_mode = "a"
+                        if 'CreateDevice' in proto.name:
+                            file_mode = "w"
+                        f_open = 'pthread_mutex_lock( &file_lock );\n    pOutFile = fopen(outFileName, "%s");\n    ' % (file_mode)
+                        log_func = 'fprintf(pOutFile, "t{%%u} xgl%s(' % proto.name
+                        f_close = '\n    fclose(pOutFile);\n    pthread_mutex_unlock( &file_lock );'
+                    else:
+                        f_open = 'pthread_mutex_lock( &print_lock );\n    '
+                        log_func = 'cout << "t{" << getTIDIndex() << "} xgl%s(' % proto.name
+                        f_close = '\n    pthread_mutex_unlock( &print_lock );'
+                    pindex = 0
+                    for p in proto.params:
+                        # TODO : Need to handle xglWsiX11CreatePresentableImage for which the last 2 params are returned vals
+                        cp = False
+                        if 0 != create_params:
+                            # If this is any of the N last params of the func, treat as output
+                            for y in range(-1, create_params-1, -1):
+                                if p.name == proto.params[y].name:
+                                    cp = True
+                        (pft, pfi) = self._get_printf_params(p.ty, p.name, cp, cpp=True)
+                        if no_addr and "%p" == pft:
+                            (pft, pfi) = ("%s", '"addr"')
+                        log_func += '%s = " << %s << ", ' % (p.name, pfi)
+                        #print_vals += ', %s' % (pfi)
+                        # TODO : Just want this to be simple check for params of STRUCT type
+                        if "pCreateInfo" in p.name or ('const' in p.ty and '*' in p.ty and False not in [tmp_ty not in p.ty for tmp_ty in ['XGL_CHAR', 'XGL_VOID', 'XGL_CMD_BUFFER', 'XGL_QUEUE_SEMAPHORE', 'XGL_FENCE', 'XGL_SAMPLER', 'XGL_UINT32']]):
+                            if 'Wsi' not in proto.name:
+                                cis_param_index.append(pindex)
+                        pindex += 1
+                    log_func = log_func.strip(', ')
+                    if proto.ret != "XGL_VOID":
+                        log_func += ') = " << string_XGL_RESULT(result) << "\\n"'
+                        #print_vals += ', string_XGL_RESULT(result)'
+                    else:
+                        log_func += ')\\n"'
+                    log_func += ';'
+                    if len(cis_param_index) > 0:
+                        log_func += '\n    string tmp_str;'
+                        for sp_index in cis_param_index:
+                            cis_print_func = 'xgl_print_%s' % (proto.params[sp_index].ty.strip('const ').strip('*').lower())
+                            log_func += '\n    if (%s) {' % (proto.params[sp_index].name)
+                            log_func += '\n        tmp_str = %s(%s, "    ");' % (cis_print_func, proto.params[sp_index].name)
+                            if "File" in layer:
+                                if no_addr:
+                                    log_func += '\n        fprintf(pOutFile, "   %s (addr)\\n%%s\\n", pTmpStr);' % (proto.params[sp_index].name)
+                                else:
+                                    log_func += '\n        fprintf(pOutFile, "   %s (%%p)\\n%%s\\n", (void*)%s, pTmpStr);' % (proto.params[sp_index].name, proto.params[sp_index].name)
+                            else:
+                                if no_addr:
+                                    #log_func += '\n        printf("   %s (addr)\\n%%s\\n", pTmpStr);' % (proto.params[sp_index].name)
+                                    log_func += '\n        cout << "   %s (addr)" << endl << tmp_str << endl;' % (proto.params[sp_index].name)
+                                else:
+                                    #log_func += '\n        printf("   %s (%%p)\\n%%s\\n", (void*)%s, pTmpStr);' % (proto.params[sp_index].name, proto.params[sp_index].name)
+                                    log_func += '\n        cout << "   %s (" << %s << ")" << endl << tmp_str << endl;' % (proto.params[sp_index].name, proto.params[sp_index].name)
+                                #log_func += '\n        fflush(stdout);'
+                            log_func += '\n    }'
+                    if proto.name == "EnumerateLayers":
+                        c_call = proto.c_call().replace("(" + proto.params[0].name, "((XGL_PHYSICAL_GPU)gpuw->nextObject", 1)
+                        funcs.append('%s%s\n'
+                                 '{\n'
+                                 '    if (gpu != NULL) {\n'
+                                 '        XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) %s;\n'
+                                 '        pCurObj = gpuw;\n'
+                                 '        pthread_once(&tabOnce, initLayerTable);\n'
+                                 '        %snextTable.%s;\n'
+                                 '        %s    %s    %s\n'
+                                 '    %s'
+                                 '    } else {\n'
+                                 '        if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL)\n'
+                                 '            return XGL_ERROR_INVALID_POINTER;\n'
+                                 '        // This layer compatible with all GPUs\n'
+                                 '        *pOutLayerCount = 1;\n'
+                                 '        strncpy((char *) pOutLayers[0], "%s", maxStringSize);\n'
+                                 '        return XGL_SUCCESS;\n'
+                                 '    }\n'
+                                     '}' % (qual, decl, proto.params[0].name, ret_val, c_call,f_open, log_func, f_close, stmt, layer_name))
+                    elif proto.params[0].ty != "XGL_PHYSICAL_GPU":
+                        funcs.append('%s%s\n'
+                                 '{\n'
+                                 '    %snextTable.%s;\n'
+                                 '    %s%s%s\n'
+                                 '%s'
+                                 '}' % (qual, decl, ret_val, proto.c_call(), f_open, log_func, f_close, stmt))
+                    else:
+                        c_call = proto.c_call().replace("(" + proto.params[0].name, "((XGL_PHYSICAL_GPU)gpuw->nextObject", 1)
+                        funcs.append('%s%s\n'
+                                 '{\n'
+                                 '    XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) %s;\n'
+                                 '    pCurObj = gpuw;\n'
+                                 '    pthread_once(&tabOnce, initLayerTable);\n'
+                                 '    %snextTable.%s;\n'
+                                 '    %s%s%s\n'
+                                 '%s'
+                                 '}' % (qual, decl, proto.params[0].name, ret_val, c_call, f_open, log_func, f_close, stmt))
                 elif "APIDump" in layer:
                     decl = proto.c_func(prefix="xgl", attr="XGLAPI")
                     param0_name = proto.params[0].name
@@ -571,7 +690,7 @@ class Subcommand(object):
         func_body.append("    else {\n"
                          "        if (gpuw->pGPA == NULL)\n"
                          "            return NULL;\n"
-                         "        return gpuw->pGPA(gpuw->nextObject, funcName);\n"
+                         "        return gpuw->pGPA((XGL_PHYSICAL_GPU)gpuw->nextObject, funcName);\n"
                          "    }\n"
                          "}\n")
         return "\n".join(func_body)
@@ -644,6 +763,36 @@ class ApiDumpSubcommand(Subcommand):
 
         return "\n\n".join(body)
 
+class ApiDumpCppSubcommand(Subcommand):
+    def generate_header(self):
+        header_txt = []
+        header_txt.append('#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <pthread.h>\n#include "xglLayer.h"\n#include "xgl_struct_string_helper_cpp.h"\n\nstatic XGL_LAYER_DISPATCH_TABLE nextTable;\nstatic XGL_BASE_LAYER_OBJECT *pCurObj;\nstatic pthread_once_t tabOnce = PTHREAD_ONCE_INIT;\npthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;\n')
+        header_txt.append('#define MAX_TID 513')
+        header_txt.append('static pthread_t tidMapping[MAX_TID] = {0};')
+        header_txt.append('static uint32_t maxTID = 0;')
+        header_txt.append('// Map actual TID to an index value and return that index')
+        header_txt.append('//  This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs')
+        header_txt.append('static uint32_t getTIDIndex() {')
+        header_txt.append('    pthread_t tid = pthread_self();')
+        header_txt.append('    for (uint32_t i = 0; i < maxTID; i++) {')
+        header_txt.append('        if (tid == tidMapping[i])')
+        header_txt.append('            return i;')
+        header_txt.append('    }')
+        header_txt.append("    // Don't yet have mapping, set it and return newly set index")
+        header_txt.append('    uint32_t retVal = (uint32_t)maxTID;')
+        header_txt.append('    tidMapping[maxTID++] = tid;')
+        header_txt.append('    assert(maxTID < MAX_TID);')
+        header_txt.append('    return retVal;')
+        header_txt.append('}')
+        return "\n".join(header_txt)
+
+    def generate_body(self):
+        body = [self._generate_layer_dispatch_table(),
+                self._generate_dispatch_entrypoints("XGL_LAYER_EXPORT", "APIDumpCpp"),
+                self._generate_layer_gpa_function()]
+
+        return "\n\n".join(body)
+
 class ApiDumpFileSubcommand(Subcommand):
     def generate_header(self):
         header_txt = []
@@ -704,6 +853,36 @@ class ApiDumpNoAddrSubcommand(Subcommand):
 
         return "\n\n".join(body)
 
+class ApiDumpNoAddrCppSubcommand(Subcommand):
+    def generate_header(self):
+        header_txt = []
+        header_txt.append('#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <assert.h>\n#include <pthread.h>\n#include "xglLayer.h"\n#include "xgl_struct_string_helper_no_addr_cpp.h"\n\nstatic XGL_LAYER_DISPATCH_TABLE nextTable;\nstatic XGL_BASE_LAYER_OBJECT *pCurObj;\nstatic pthread_once_t tabOnce = PTHREAD_ONCE_INIT;\npthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER;\n')
+        header_txt.append('#define MAX_TID 513')
+        header_txt.append('static pthread_t tidMapping[MAX_TID] = {0};')
+        header_txt.append('static uint32_t maxTID = 0;')
+        header_txt.append('// Map actual TID to an index value and return that index')
+        header_txt.append('//  This keeps TIDs in range from 0-MAX_TID and simplifies compares between runs')
+        header_txt.append('static uint32_t getTIDIndex() {')
+        header_txt.append('    pthread_t tid = pthread_self();')
+        header_txt.append('    for (uint32_t i = 0; i < maxTID; i++) {')
+        header_txt.append('        if (tid == tidMapping[i])')
+        header_txt.append('            return i;')
+        header_txt.append('    }')
+        header_txt.append("    // Don't yet have mapping, set it and return newly set index")
+        header_txt.append('    uint32_t retVal = (uint32_t)maxTID;')
+        header_txt.append('    tidMapping[maxTID++] = tid;')
+        header_txt.append('    assert(maxTID < MAX_TID);')
+        header_txt.append('    return retVal;')
+        header_txt.append('}')
+        return "\n".join(header_txt)
+
+    def generate_body(self):
+        body = [self._generate_layer_dispatch_table(),
+                self._generate_dispatch_entrypoints("XGL_LAYER_EXPORT", "APIDumpCpp", True),
+                self._generate_layer_gpa_function()]
+
+        return "\n\n".join(body)
+
 class ObjectTrackerSubcommand(Subcommand):
     def generate_header(self):
         header_txt = []
@@ -915,6 +1094,8 @@ def main():
             "ApiDump" : ApiDumpSubcommand,
             "ApiDumpFile" : ApiDumpFileSubcommand,
             "ApiDumpNoAddr" : ApiDumpNoAddrSubcommand,
+            "ApiDumpCpp" : ApiDumpCppSubcommand,
+            "ApiDumpNoAddrCpp" : ApiDumpNoAddrCppSubcommand,
             "ObjectTracker" : ObjectTrackerSubcommand,
     }