layers: Add dependency info to vk_extension_helper

Add additional metadata to *Extensions structs to enable extension
dependency validation at CreateInstance CreateDevice time.

Refactor the code generator for the extension helper prior to
refactoring the generated code to address an incomplete.

Change-Id: I79ae680d9c41f1f153ee8108d4deac8ec8c5a886
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index 1f7dda6..d7bb25e 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -167,7 +167,12 @@
         name_define = nameElem.get('name')
         if 'EXTENSION_NAME' not in name_define:
             print("Error in vk.xml file -- extension name is not available")
-        info = {'define': name_define, 'ifdef': self.featureExtraProtect}
+        requires = interface.get('requires')
+        if requires is not None:
+            required_extensions = requires.split(',')
+        else:
+            required_extensions = list()
+        info = { 'define': name_define, 'ifdef':self.featureExtraProtect, 'reqs':required_extensions }
         if interface.get('type') == 'instance':
             self.instance_extension_info[name] = info
         else:
@@ -494,10 +499,11 @@
             '',
             '#ifndef VK_EXTENSION_HELPER_H_',
             '#define VK_EXTENSION_HELPER_H_',
-            '#include <vulkan/vulkan.h>',
-            '#include <string.h>',
+            '#include <string>',
+            '#include <unordered_map>',
             '#include <utility>',
             '',
+            '#include <vulkan/vulkan.h>',
             '']
 
         def guarded(ifdef, value):
@@ -523,10 +529,62 @@
             field_name = { ext_name: re.sub('_extension_name', '', info['define'].lower()) for ext_name, info in extension_items }
             if type == 'Instance':
                 instance_field_name = field_name
+                instance_extension_dict = extension_dict
+            else:
+                # Get complete field name and extension data for both Instance and Device extensions
+                field_name.update(instance_field_name)
+                extension_dict = extension_dict.copy()  # Don't modify the self.<dict> we're pointing to
+                extension_dict.update(instance_extension_dict)
 
+            # Output the data member list
             struct  = [struct_decl]
             struct.extend([ '    bool %s{false};' % field_name[ext_name] for ext_name, info in extension_items])
-            struct.append('')
+
+            # Construct the extension information map -- mapping name to data member (field), and required extensions
+            # The map is contained within a static function member for portability reasons.
+            info_type = '%sInfo' % type
+            info_map_type = '%sMap' % info_type
+            req_type = '%sReq' % type
+            req_vec_type = '%sVec' % req_type
+            struct.extend([
+                '',
+                '    struct %s {' % req_type,
+                '        const bool %s::* enabled;' % struct_type,
+                '        const char *name;',
+                '    };',
+                '    typedef std::vector<%s> %s;' % (req_type, req_vec_type),
+                '    struct %s {' % info_type,
+                '       %s(bool %s::* state_, const %s requires_): state(state_), requires(requires_) {}' % ( info_type, struct_type, req_vec_type),
+                '       bool %s::* state;' % struct_type,
+                '       %s requires;' % req_vec_type,
+                '    };',
+                '',
+                '    typedef std::unordered_map<std::string,%s> %s;' % (info_type, info_map_type),
+                '    static const %s &get_info(const char *name) {' %info_type,
+                '        static const %s info_map = {' % info_map_type ])
+
+            field_format = '&' + struct_type + '::%s'
+            req_format = '{' + field_format+ ', %s}'
+            req_indent = '\n                           '
+            req_join = ',' + req_indent
+            info_format = ('            std::make_pair(%s, ' + info_type + '(' + field_format + ', {%s})),')
+            def format_info(ext_name, info):
+                reqs = req_join.join([req_format % (field_name[req], extension_dict[req]['define']) for req in info['reqs']])
+                return info_format % (info['define'], field_name[ext_name], '{%s}' % (req_indent + reqs) if reqs else '')
+
+            struct.extend([guarded(info['ifdef'], format_info(ext_name, info)) for ext_name, info in extension_items])
+            struct.extend([
+                '        };',
+                '',
+                '        static const %s empty_info {nullptr, %s()};' % (info_type, req_vec_type),
+                '        %s::const_iterator info = info_map.find(name);' % info_map_type,
+                '        if ( info != info_map.cend()) {',
+                '            return info->second;',
+                '        }',
+                '        return empty_info;',
+                '    }',
+                ''])
+
             if type == 'Instance':
                 struct.extend([
                     '    uint32_t NormalizeApiVersion(uint32_t specified_version) {',
@@ -537,8 +595,14 @@
                     '    uint32_t InitFromInstanceCreateInfo(uint32_t requested_api_version, const VkInstanceCreateInfo *pCreateInfo) {'])
             else:
                 struct.extend([
-                    '    uint32_t InitFromDeviceCreateInfo(const InstanceExtensions *instance_extensions, uint32_t requested_api_version,',
-                    '                                      const VkDeviceCreateInfo *pCreateInfo) {'])
+                    '    %s() = default;' % struct_type,
+                    '    %s(const %s& instance_ext) : %s(instance_ext) {}' % (struct_type, instance_struct_type, instance_struct_type),
+                    '',
+                    '    uint32_t InitFromDeviceCreateInfo(const %s *instance_extensions, uint32_t requested_api_version,' % instance_struct_type,
+                    '                                      const VkDeviceCreateInfo *pCreateInfo) {',
+                    '        // Initialize: this to defaults,  base class fields to input.',
+                    '        assert(instance_extensions);',
+                    '        *this = %s(*instance_extensions);' % struct_type])
 
             struct.extend([
                 '',
@@ -547,45 +611,28 @@
             struct.extend([
                 '        };',
                 '',
-                '        static const std::pair<char const *, bool %sExtensions::*> known_extensions[]{' % type])
-            init_format = '            {%s, &' + type + 'Extensions::%s},'
-            struct.extend([guarded(info['ifdef'], init_format % (info['define'], field_name[ext_name])) for ext_name, info in extension_items])
-            struct.extend([
-                '        };',
-                '',
-                '        // Initialize struct data'])
-
-            if type == 'Device':
-                struct.extend([ '        %s = instance_extensions->%s;' % (name, name) for name in sorted(instance_field_name.values()) ])    
-
-            struct.extend([
-                '',
-                '        for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {',
-                '            for (auto ext : known_extensions) {',
-                '                if (!strcmp(ext.first, pCreateInfo->ppEnabledExtensionNames[i])) {',
-                '                    this->*(ext.second) = true;',
-                '                    break;',
-                '                }',
+                '        // Initialize struct data, robust to invalid pCreateInfo',
+                '        if (pCreateInfo->ppEnabledExtensionNames) {',
+                '            for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {',
+                '                if (!pCreateInfo->ppEnabledExtensionNames[i]) continue;',
+                '                auto info = get_info(pCreateInfo->ppEnabledExtensionNames[i]);',
+                '                if(info.state) this->*(info.state) = true;',
                 '            }',
                 '        }',
                 '        uint32_t api_version = NormalizeApiVersion(requested_api_version);',
                 '        if (api_version >= VK_API_VERSION_1_1) {',
                 '            for (auto promoted_ext : V_1_0_promoted_%s_extensions) {' % type.lower(),
-                '                for (auto ext : known_extensions) {',
-                '                    if (!strcmp(ext.first, promoted_ext)) {',
-                '                        this->*(ext.second) = true;',
-                '                        break;',
-                '                    }',
-                '                }',
+                '                auto info = get_info(promoted_ext);',
+                '                assert(info.state);',
+                '                if (info.state) this->*(info.state) = true;',
                 '            }',
                 '        }',
                 '        return api_version;',
                 '    }',
-                '};',
-                ''])
+                '};'])
 
             # Output reference lists of instance/device extension names
-            struct.append('static const char * const k%sExtensionNames = ' % type)
+            struct.extend(['', 'static const char * const k%sExtensionNames = ' % type])
             struct.extend([guarded(info['ifdef'], '    %s' % info['define']) for ext_name, info in extension_items])
             struct.extend([';', ''])
             output.extend(struct)