layers: Add typesafety traits

Add traits (present for dispatchable and for non-dispatchable 64 bit) to
improve type safety and enabled enhanced handle logging

Further typesafety changes will build on this in subsequent commits.

Change-Id: Ife7017df9c2516994407663cb2ebaaecc620a336
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index c110579..35ea403 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -659,7 +659,6 @@
         object_types_helper_header = '\n'
         object_types_helper_header += '#pragma once\n'
         object_types_helper_header += '\n'
-        object_types_helper_header += '#include <vulkan/vulkan.h>\n\n'
         object_types_helper_header += self.GenerateObjectTypesHeader()
         return object_types_helper_header
     #
@@ -672,6 +671,9 @@
         enum_num = 1
         type_list = [];
         enum_entry_map = {}
+        non_dispatchable = {}
+        dispatchable = {}
+        object_type_info = {}
 
         # Output enum definition as each handle is processed, saving the names to use for the conversion routine
         for item in self.object_types:
@@ -682,6 +684,13 @@
             object_types_header += ' = %d,\n' % enum_num
             enum_num += 1
             type_list.append(enum_entry)
+            object_type_info[enum_entry] = { 'VkType': item }
+            # We'll want lists of the dispatchable and non dispatchable handles below with access to the same info
+            if IsHandleTypeNonDispatchable(self.registry.tree, item) :
+                non_dispatchable[item] = enum_entry
+            else:
+                dispatchable[item] = enum_entry
+
         object_types_header += '    kVulkanObjectTypeMax = %d,\n' % enum_num
         object_types_header += '    // Aliases for backwards compatibilty of "promoted" types\n'
         for (name, alias) in self.object_type_aliases:
@@ -711,9 +720,11 @@
         dbg_re = '^VK_DEBUG_REPORT_OBJECT_TYPE_(.*)_EXT$'
         dbg_map = {to_key(dbg_re, dbg) : dbg for dbg in self.debug_report_object_types}
         dbg_default = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT'
+
         for object_type in type_list:
             vk_object_type = dbg_map.get(object_type.replace("kVulkanObjectType", "").lower(), dbg_default)
             object_types_header += '    %s,   // %s\n' % (vk_object_type, object_type)
+            object_type_info[object_type]['DbgType'] = vk_object_type
         object_types_header += '};\n'
 
         # Output a conversion routine from the layer object definitions to the core object type definitions
@@ -728,6 +739,7 @@
         for object_type in type_list:
             vk_object_type = vko_map[object_type.replace("kVulkanObjectType", "").lower()]
             object_types_header += '    %s,   // %s\n' % (vk_object_type, object_type)
+            object_type_info[object_type]['VkoType'] = vk_object_type
         object_types_header += '};\n'
 
         # Create a function to convert from VkDebugReportObjectTypeEXT to VkObjectType
@@ -771,6 +783,62 @@
         object_types_header += '    }\n'
         object_types_header += '    return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n'
         object_types_header += '}\n'
+
+        traits_format = Outdent('''
+            template <> struct VkHandleInfo<{vk_type}> {{
+                static const VulkanObjectType kVulkanObjectType = {obj_type};
+                static const VkDebugReportObjectTypeEXT kDebugReportObjectType = {dbg_type};
+                static const VkObjectType kVkObjectType = {vko_type};
+                static const char* Typename() {{
+                    return "{vk_type}";
+                }}
+            }};
+            template <> struct VulkanObjectTypeInfo<{obj_type}> {{
+                typedef {vk_type} Type;
+            }};
+            ''')
+
+        object_types_header += Outdent('''
+            // Traits objects from each type statically map from Vk<handleType> to the various enums
+            template <typename VkType> struct VkHandleInfo {};
+            template <VulkanObjectType id> struct VulkanObjectTypeInfo {};
+
+            // The following line must match the vulkan_core.h condition guarding VK_DEFINE_NON_DISPATCHABLE_HANDLE
+            #if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || \
+                defined(_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+            #define TYPESAFE_NONDISPATCHABLE_HANDLES
+            #else
+            VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkNonDispatchableHandle)
+            ''')  +'\n'
+        object_types_header += traits_format.format(vk_type='VkNonDispatchableHandle', obj_type='kVulkanObjectTypeUnknown',
+                                                  dbg_type='VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT',
+                                                  vko_type='VK_OBJECT_TYPE_UNKNOWN') + '\n'
+        object_types_header += '#endif //  VK_DEFINE_HANDLE logic duplication\n'
+
+        for vk_type, object_type in dispatchable.items():
+            info = object_type_info[object_type]
+            object_types_header += traits_format.format(vk_type=vk_type, obj_type=object_type, dbg_type=info['DbgType'],
+                                                      vko_type=info['VkoType'])
+        object_types_header += '#ifdef TYPESAFE_NONDISPATCHABLE_HANDLES\n'
+        for vk_type, object_type in non_dispatchable.items():
+            info = object_type_info[object_type]
+            object_types_header += traits_format.format(vk_type=vk_type, obj_type=object_type, dbg_type=info['DbgType'],
+                                                      vko_type=info['VkoType'])
+        object_types_header += '#endif // TYPESAFE_NONDISPATCHABLE_HANDLES\n'
+
+        object_types_header += Outdent('''
+            struct VulkanTypedHandle {
+                uint64_t handle;
+                VulkanObjectType type;
+                template <typename Handle>
+                VulkanTypedHandle(Handle handle_) :
+                    handle(reinterpret_cast<uint64_t>(handle_)),
+                    type(VkHandleInfo<Handle>::kVulkanObjectType) {}
+                VulkanTypedHandle() :
+                    handle(VK_NULL_HANDLE),
+                    type(kVulkanObjectTypeUnknown) {}
+            }; ''')  +'\n'
+
         return object_types_header
     #
     # Determine if a structure needs a safe_struct helper function