layers: Refactored pNext chain walks to template
authorJohn Zulauf <jzulauf@lunarg.com>
Thu, 26 Oct 2017 18:07:05 +0000 (12:07 -0600)
committerjzulauf-lunarg <32470354+jzulauf-lunarg@users.noreply.github.com>
Fri, 3 Nov 2017 15:31:30 +0000 (09:31 -0600)
The while loops for the walking the pNext chains were implemented by
repeated code. These were refactored into a common template.  Added
autogenerated 'traits' objects for the pNext linked structs.

Delete cut and paste duplicate pNext chain walk.

Change-Id: I46457bb5432219c74f9356e5230c70e4a9ef16df

CMakeLists.txt
build-android/android-generate.bat
build-android/android-generate.sh
layers/core_validation.cpp
layers/parameter_validation_utils.cpp
scripts/helper_file_generator.py
scripts/lvl_genvk.py

index 0d3b157..2412236 100644 (file)
@@ -316,6 +316,7 @@ add_custom_target(generate_helper_files DEPENDS
     vk_layer_dispatch_table.h
     vk_dispatch_table_helper.h
     vk_extension_helper.h
+    vk_typemap_helper.h
     )
 
 # Rules to build generated helper files
@@ -328,6 +329,7 @@ run_vk_xml_generate(helper_file_generator.py vk_struct_size_helper.c)
 run_vk_xml_generate(helper_file_generator.py vk_enum_string_helper.h)
 run_vk_xml_generate(helper_file_generator.py vk_object_types.h)
 run_vk_xml_generate(helper_file_generator.py vk_extension_helper.h)
+run_vk_xml_generate(helper_file_generator.py vk_typemap_helper.h)
 
 if(NOT WIN32)
     include(GNUInstallDirs)
index 8f4bab9..d305abc 100644 (file)
@@ -33,5 +33,6 @@ py -3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml unique_obj
 py -3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_layer_dispatch_table.h
 py -3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_extension_helper.h
 py -3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml object_tracker.cpp
+py -3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_typemap_helper.h
 cd ../..
 
index 9b1d94b..80687d9 100755 (executable)
@@ -36,5 +36,6 @@ mkdir -p generated/include generated/common
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_layer_dispatch_table.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_extension_helper.h )
 ( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml object_tracker.cpp )
+( cd generated/include; python3 ../../../scripts/lvl_genvk.py -registry ../../../scripts/vk.xml vk_typemap_helper.h )
 
 exit 0
index 57bce8c..8431972 100644 (file)
@@ -67,6 +67,7 @@
 #include "vk_layer_data.h"
 #include "vk_layer_extension_utils.h"
 #include "vk_layer_utils.h"
+#include "vk_typemap_helper.h"
 
 #if defined __ANDROID__
 #include <android/log.h>
@@ -1941,7 +1942,7 @@ static void init_core_validation(instance_layer_data *instance_data, const VkAll
 }
 
 // For the given ValidationCheck enum, set all relevant instance disabled flags to true
-void SetDisabledFlags(instance_layer_data *instance_data, VkValidationFlagsEXT *val_flags_struct) {
+void SetDisabledFlags(instance_layer_data *instance_data, const VkValidationFlagsEXT *val_flags_struct) {
     for (uint32_t i = 0; i < val_flags_struct->disabledValidationCheckCount; ++i) {
         switch (val_flags_struct->pDisabledValidationChecks[i]) {
             case VK_VALIDATION_CHECK_SHADERS_EXT:
@@ -1982,15 +1983,9 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateInstance(const VkInstanceCreateInfo *pCreat
 
     ValidateLayerOrdering(*pCreateInfo);
     // Parse any pNext chains
-    if (pCreateInfo->pNext) {
-        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
-        while (struct_header) {
-            // Check for VkValidationFlagsExt
-            if (VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT == struct_header->sType) {
-                SetDisabledFlags(instance_data, (VkValidationFlagsEXT *)struct_header);
-            }
-            struct_header = (GENERIC_HEADER *)struct_header->pNext;
-        }
+    const auto *validation_flags_ext = lvl_find_in_chain<VkValidationFlagsEXT>(pCreateInfo->pNext);
+    if (validation_flags_ext) {
+        SetDisabledFlags(instance_data, validation_flags_ext);
     }
 
     return result;
@@ -2142,15 +2137,9 @@ VKAPI_ATTR VkResult VKAPI_CALL CreateDevice(VkPhysicalDevice gpu, const VkDevice
     // The enabled features can come from either pEnabledFeatures, or from the pNext chain
     const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
     if (nullptr == enabled_features_found) {
-        GENERIC_HEADER *struct_header = (GENERIC_HEADER *)pCreateInfo->pNext;
-        while (struct_header) {
-            if (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR == struct_header->sType) {
-                VkPhysicalDeviceFeatures2KHR *features2 = (VkPhysicalDeviceFeatures2KHR *)struct_header;
-                enabled_features_found =  &(features2->features);
-                struct_header = nullptr;
-            } else {
-                struct_header = (GENERIC_HEADER *)struct_header->pNext;
-            }
+        const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
+        if (features2) {
+            enabled_features_found = &(features2->features);
         }
     }
 
@@ -9746,52 +9735,51 @@ VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInf
     }
     if (pPresentInfo && pPresentInfo->pNext) {
         // Verify ext struct
-        GENERIC_HEADER *pnext = (GENERIC_HEADER *)pPresentInfo->pNext;
-        while (pnext) {
-            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
-                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
-                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
-                    auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
-                    assert(swapchain_data);
-                    VkPresentRegionKHR region = present_regions->pRegions[i];
-                    for (uint32_t j = 0; j < region.rectangleCount; ++j) {
-                        VkRectLayerKHR rect = region.pRectangles[j];
-                        // TODO: Need to update these errors to their unique error ids when available
-                        if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
-                            skip |= log_msg(
-                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
-                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
-                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
-                                "(%i) and extent.width (%i) is greater than the "
-                                "corresponding swapchain's imageExtent.width (%i).",
-                                i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
-                        }
-                        if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
-                            skip |= log_msg(
-                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
-                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
-                                "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
-                                "(%i) and extent.height (%i) is greater than the "
-                                "corresponding swapchain's imageExtent.height (%i).",
-                                i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
-                        }
-                        if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
-                            skip |= log_msg(
-                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
-                                HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
-                                "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
-                                "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
-                                i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
-                        }
+        const auto *present_regions = lvl_find_in_chain<VkPresentRegionsKHR>(pPresentInfo->pNext);
+        if (present_regions) {
+            for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
+                auto swapchain_data = GetSwapchainNode(dev_data, pPresentInfo->pSwapchains[i]);
+                assert(swapchain_data);
+                VkPresentRegionKHR region = present_regions->pRegions[i];
+                for (uint32_t j = 0; j < region.rectangleCount; ++j) {
+                    VkRectLayerKHR rect = region.pRectangles[j];
+                    // TODO: Need to update these errors to their unique error ids when available
+                    if ((rect.offset.x + rect.extent.width) > swapchain_data->createInfo.imageExtent.width) {
+                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                        VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
+                                        __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
+                                        "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
+                                        "chain, pRegion[%i].pRectangles[%i], the sum of offset.x "
+                                        "(%i) and extent.width (%i) is greater than the "
+                                        "corresponding swapchain's imageExtent.width (%i).",
+                                        i, j, rect.offset.x, rect.extent.width, swapchain_data->createInfo.imageExtent.width);
+                    }
+                    if ((rect.offset.y + rect.extent.height) > swapchain_data->createInfo.imageExtent.height) {
+                        skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                        VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT, HandleToUint64(pPresentInfo->pSwapchains[i]),
+                                        __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
+                                        "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext "
+                                        "chain, pRegion[%i].pRectangles[%i], the sum of offset.y "
+                                        "(%i) and extent.height (%i) is greater than the "
+                                        "corresponding swapchain's imageExtent.height (%i).",
+                                        i, j, rect.offset.y, rect.extent.height, swapchain_data->createInfo.imageExtent.height);
+                    }
+                    if (rect.layer > swapchain_data->createInfo.imageArrayLayers) {
+                        skip |= log_msg(
+                            dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                            HandleToUint64(pPresentInfo->pSwapchains[i]), __LINE__, DRAWSTATE_SWAPCHAIN_INVALID_IMAGE, "DS",
+                            "vkQueuePresentKHR(): For VkPresentRegionKHR down pNext chain, pRegion[%i].pRectangles[%i], the "
+                            "layer (%i) is greater than the corresponding swapchain's imageArrayLayers (%i).",
+                            i, j, rect.layer, swapchain_data->createInfo.imageArrayLayers);
                     }
                 }
-            } else if (VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE == pnext->sType) {
-                VkPresentTimesInfoGOOGLE *present_times_info = (VkPresentTimesInfoGOOGLE *)pnext;
-                if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
-                    skip |=
-                        log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+            }
+        }
+
+        const auto *present_times_info = lvl_find_in_chain<VkPresentTimesInfoGOOGLE>(pPresentInfo->pNext);
+        if (present_times_info) {
+            if (pPresentInfo->swapchainCount != present_times_info->swapchainCount) {
+                skip |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
                                 HandleToUint64(pPresentInfo->pSwapchains[0]), __LINE__,
 
                                 VALIDATION_ERROR_118009be, "DS",
@@ -9800,9 +9788,7 @@ VKAPI_ATTR VkResult VKAPI_CALL QueuePresentKHR(VkQueue queue, const VkPresentInf
                                 "chain of VkPresentInfoKHR, VkPresentTimesInfoGOOGLE.swapchainCount "
                                 "must equal VkPresentInfoKHR.swapchainCount.",
                                 present_times_info->swapchainCount, pPresentInfo->swapchainCount);
-                }
             }
-            pnext = (GENERIC_HEADER *)pnext->pNext;
         }
     }
 
index 2a7511a..d115b4f 100644 (file)
@@ -39,6 +39,7 @@
 #include "vulkan/vk_layer.h"
 #include "vk_layer_config.h"
 #include "vk_dispatch_table_helper.h"
+#include "vk_typemap_helper.h"
 
 #include "vk_layer_table.h"
 #include "vk_layer_data.h"
@@ -354,40 +355,13 @@ static bool ValidateDeviceCreateInfo(instance_layer_data *instance_data, VkPhysi
 
     if (pCreateInfo->pNext != NULL && pCreateInfo->pEnabledFeatures) {
         // Check for get_physical_device_properties2 struct
-        struct std_header {
-            VkStructureType sType;
-            const void *pNext;
-        };
-        std_header *cur_pnext = (std_header *)pCreateInfo->pNext;
-        while (cur_pnext) {
-            if (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR == cur_pnext->sType) {
-                // Cannot include VkPhysicalDeviceFeatures2KHR and have non-null pEnabledFeatures
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
-                                0, __LINE__, INVALID_USAGE, LayerName,
-                                "VkDeviceCreateInfo->pNext includes a VkPhysicalDeviceFeatures2KHR struct when "
-                                "pCreateInfo->pEnabledFeatures is non-NULL.");
-                break;
-            }
-            cur_pnext = (std_header *)cur_pnext->pNext;
-        }
-    }
-    if (pCreateInfo->pNext != NULL && pCreateInfo->pEnabledFeatures) {
-        // Check for get_physical_device_properties2 struct
-        struct std_header {
-            VkStructureType sType;
-            const void *pNext;
-        };
-        std_header *cur_pnext = (std_header *)pCreateInfo->pNext;
-        while (cur_pnext) {
-            if (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR == cur_pnext->sType) {
-                // Cannot include VkPhysicalDeviceFeatures2KHR and have non-null pEnabledFeatures
-                skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
-                                0, __LINE__, INVALID_USAGE, LayerName,
-                                "VkDeviceCreateInfo->pNext includes a VkPhysicalDeviceFeatures2KHR struct when "
-                                "pCreateInfo->pEnabledFeatures is non-NULL.");
-                break;
-            }
-            cur_pnext = (std_header *)cur_pnext->pNext;
+        const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
+        if (features2) {
+            // Cannot include VkPhysicalDeviceFeatures2KHR and have non-null pEnabledFeatures
+            skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                            __LINE__, INVALID_USAGE, LayerName,
+                            "VkDeviceCreateInfo->pNext includes a VkPhysicalDeviceFeatures2KHR struct when "
+                            "pCreateInfo->pEnabledFeatures is non-NULL.");
         }
     }
 
@@ -501,15 +475,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(VkPhysicalDevice physicalDevice, c
             // The enabled features can come from either pEnabledFeatures, or from the pNext chain
             const VkPhysicalDeviceFeatures *enabled_features_found = pCreateInfo->pEnabledFeatures;
             if ((nullptr == enabled_features_found) && my_device_data->extensions.vk_khr_get_physical_device_properties_2) {
-                const GenericHeader *current = reinterpret_cast<const GenericHeader *>(pCreateInfo->pNext);
-                while (current) {
-                    if (VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR == current->sType) {
-                        const VkPhysicalDeviceFeatures2KHR *features2 = reinterpret_cast<const VkPhysicalDeviceFeatures2KHR *>(current);
-                        enabled_features_found = &(features2->features);
-                        current = nullptr;
-                    } else {
-                        current = reinterpret_cast<const GenericHeader *>(current->pNext);
-                    }
+                const auto *features2 = lvl_find_in_chain<VkPhysicalDeviceFeatures2KHR>(pCreateInfo->pNext);
+                if (features2) {
+                    enabled_features_found = &(features2->features);
                 }
             }
             if (enabled_features_found) {
@@ -2291,39 +2259,29 @@ bool pv_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) {
     layer_data *device_data = GetLayerDataPtr(get_dispatch_key(queue), layer_data_map);
 
     if (pPresentInfo && pPresentInfo->pNext) {
-        // Verify ext struct
-        struct std_header {
-            VkStructureType sType;
-            const void *pNext;
-        };
-        std_header *pnext = (std_header *)pPresentInfo->pNext;
-        while (pnext) {
-            if (VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR == pnext->sType) {
-                // TODO: This and all other pNext extension dependencies should be added to code-generation
-                skip |= require_device_extension(device_data, device_data->extensions.vk_khr_incremental_present,
-                                                 "vkQueuePresentKHR", VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
-                VkPresentRegionsKHR *present_regions = (VkPresentRegionsKHR *)pnext;
-                if (present_regions->swapchainCount != pPresentInfo->swapchainCount) {
-                    skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, __LINE__, INVALID_USAGE, LayerName,
-                                    "QueuePresentKHR(): pPresentInfo->swapchainCount has a value of %i"
-                                    " but VkPresentRegionsKHR extension swapchainCount is %i. These values must be equal.",
-                                    pPresentInfo->swapchainCount, present_regions->swapchainCount);
-                }
-                skip |= validate_struct_pnext(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pNext", NULL,
-                                              present_regions->pNext, 0, NULL, GeneratedHeaderVersion, VALIDATION_ERROR_1121c40d);
-                skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->swapchainCount",
-                                       "pCreateInfo->pNext->pRegions", present_regions->swapchainCount, present_regions->pRegions,
-                                       true, false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
-                for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
-                    skip |=
-                        validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pRegions[].rectangleCount",
+        const auto *present_regions = lvl_find_in_chain<VkPresentRegionsKHR>(pPresentInfo->pNext);
+        if (present_regions) {
+            // TODO: This and all other pNext extension dependencies should be added to code-generation
+            skip |= require_device_extension(device_data, device_data->extensions.vk_khr_incremental_present, "vkQueuePresentKHR",
+                                             VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME);
+            if (present_regions->swapchainCount != pPresentInfo->swapchainCount) {
+                skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
+                                __LINE__, INVALID_USAGE, LayerName,
+                                "QueuePresentKHR(): pPresentInfo->swapchainCount has a value of %i"
+                                " but VkPresentRegionsKHR extension swapchainCount is %i. These values must be equal.",
+                                pPresentInfo->swapchainCount, present_regions->swapchainCount);
+            }
+            skip |= validate_struct_pnext(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pNext", NULL,
+                                          present_regions->pNext, 0, NULL, GeneratedHeaderVersion, VALIDATION_ERROR_1121c40d);
+            skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->swapchainCount",
+                                   "pCreateInfo->pNext->pRegions", present_regions->swapchainCount, present_regions->pRegions, true,
+                                   false, VALIDATION_ERROR_UNDEFINED, VALIDATION_ERROR_UNDEFINED);
+            for (uint32_t i = 0; i < present_regions->swapchainCount; ++i) {
+                skip |= validate_array(device_data->report_data, "QueuePresentKHR", "pCreateInfo->pNext->pRegions[].rectangleCount",
                                        "pCreateInfo->pNext->pRegions[].pRectangles", present_regions->pRegions[i].rectangleCount,
                                        present_regions->pRegions[i].pRectangles, true, false, VALIDATION_ERROR_UNDEFINED,
                                        VALIDATION_ERROR_UNDEFINED);
-                }
             }
-            pnext = (std_header *)pnext->pNext;
         }
     }
 
index 3d4ef46..a8e9f13 100644 (file)
@@ -130,6 +130,7 @@ class HelperFileOutputGenerator(OutputGenerator):
         copyright += ' * Author: Courtney Goeltzenleuchter <courtneygo@google.com>\n'
         copyright += ' * Author: Tobin Ehlis <tobine@google.com>\n'
         copyright += ' * Author: Chris Forbes <chrisforbes@google.com>\n'
+        copyright += ' * Author: John Zulauf<jzulauf@lunarg.com>\n'
         copyright += ' *\n'
         copyright += ' ****************************************************************************/\n'
         write(copyright, file=self.outFile)
@@ -919,6 +920,112 @@ class HelperFileOutputGenerator(OutputGenerator):
                 safe_struct_body.append("#endif // %s\n" % item.ifdef_protect)
         return "\n".join(safe_struct_body)
     #
+    # Generate the type map
+    def GenerateTypeMapHelperHeader(self):
+        prefix = 'Lvl'
+        fprefix = 'lvl_'
+        typemap = prefix + 'TypeMap'
+        idmap = prefix + 'STypeMap'
+        name_member = 'kName'
+        type_member = 'Type'
+        id_member = 'kSType'
+        decl_prefix ='constexpr static'
+        char_decl = decl_prefix + ' const char *'
+        id_decl = decl_prefix + ' const VkStructureType '
+        generic_header = prefix + 'GenericHeader'
+        typename_func = fprefix + 'typename'
+        idname_func = fprefix + 'stype_name'
+        find_func = fprefix + 'find_in_chain'
+
+        explanatory_comment = '\n'.join((
+                '// These empty generic templates are specialized for each type with sType',
+                '// members and for each sType -- providing a two way map between structure',
+                '// types and sTypes as well as a kName stringification for convenience'))
+
+        empty_typemap = 'template <typename T> struct ' + typemap + ' {};'
+        typemap_format  = 'template <> struct {template}<{typename}> {{\n'
+        typemap_format += '    {char_decl}{name} = "{typename}";\n'
+        typemap_format += '    {id_decl}{id_member} = {id_value};\n'
+        typemap_format += '}};\n'
+
+        empty_idmap = 'template <VkStructureType id> struct ' + idmap + ' {};'
+        idmap_format = ''.join((
+            'template <> struct {template}<{id_value}> {{\n',
+            '    typedef {typename} {typedef};\n',
+            '    {char_decl}{name} = "{id_value}";\n',
+            '}};\n'))
+
+        # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file
+        utilities_format = '\n'.join((
+            '// Header "base class" for pNext chain traversal',
+            'struct {header} {{',
+            '   VkStructureType sType;',
+            '   const {header} *pNext;',
+            '}};',
+            '',
+            '// Find an entry of the given type in the pNext chain',
+            'template <typename T> const T *{find_func}(const void *next) {{',
+            '    const {header} *current = reinterpret_cast<const {header} *>(next);',
+            '    const T *found = nullptr;',
+            '    while (current) {{',
+            '        if ({type_map}<T>::{id_member} == current->sType) {{',
+            '            found = reinterpret_cast<const T*>(current);',
+            '            current = nullptr;',
+            '        }} else {{',
+            '            current = current->pNext;',
+            '        }}',
+            '    }}',
+            '    return found;',
+            '}}',
+            '',
+            '// Convenience functions for accessing the other mapped objects name field',
+            'template <typename T> constexpr const char *{idname_func}() {{',
+            '    return {id_map}<{type_map}<T>::{id_member}>::{name_member};',
+            '}}',
+            'template <VkStructureType s_type> constexpr const char *{typename_func}() {{',
+            '    return {type_map}<typename {id_map}<s_type>::{type_member}>::{name_member};',
+            '}}'))
+
+        code = []
+        code.append('\n'.join((
+            '#pragma once',
+            '#include <vulkan/vulkan.h>\n',
+            explanatory_comment, '',
+            empty_idmap,
+            empty_typemap, '',
+            utilities_format.format(name_member=name_member, id_member=id_member, id_map=idmap, type_map=typemap,
+                type_member=type_member, header=generic_header, typename_func=typename_func, idname_func=idname_func,
+                find_func=find_func), ''
+            )))
+
+        # Generate the specializations for each type and stype
+
+        for item in self.structMembers:
+            typename = item.name
+            info = self.structTypes.get(typename)
+            if not info:
+                continue
+
+            if item.ifdef_protect != None:
+                code.append('#ifdef %s' % item.ifdef_protect)
+
+            code.append('// Map type {} to id {}'.format(typename, info.value))
+            code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value,
+                char_decl=char_decl, id_decl=id_decl, name=name_member, id_member=id_member))
+            code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, char_decl=char_decl, typedef=type_member, name=name_member))
+
+            if item.ifdef_protect != None:
+                code.append('#endif // %s' % item.ifdef_protect)
+
+        #for typename, info in self.structTypes.items():
+        #    code.append("// Map type {} to id {}".format(typename, info.value))
+        #    code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value,
+        #        char_decl=char_decl, id_decl=id_decl, name=name_member, id_member=id_member))
+        #    code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, char_decl=char_decl, typedef=type_member, name=name_member))
+
+        return "\n".join(code)
+
+    #
     # Create a helper file and return it as a string
     def OutputDestFile(self):
         if self.helper_file_type == 'enum_string_header':
@@ -935,6 +1042,8 @@ class HelperFileOutputGenerator(OutputGenerator):
             return self.GenerateObjectTypesHelperHeader()
         elif self.helper_file_type == 'extension_helper_header':
             return self.GenerateExtensionHelperHeader()
+        elif self.helper_file_type == 'typemap_helper_header':
+            return self.GenerateTypeMapHelperHeader()
         else:
             return 'Bad Helper File Generator Option %s' % self.helper_file_type
 
index 09554db..7c81f51 100644 (file)
@@ -424,6 +424,28 @@ def makeGenOpts(extensions = [], removeExtensions = [], protect = True, director
             helper_file_type  = 'extension_helper_header')
         ]
 
+    # Helper file generator options for typemap_helper.h
+    genOpts['vk_typemap_helper.h'] = [
+          HelperFileOutputGenerator,
+          HelperFileOutputGeneratorOptions(
+            filename          = 'vk_typemap_helper.h',
+            directory         = directory,
+            apiname           = 'vulkan',
+            profile           = None,
+            versions          = allVersions,
+            emitversions      = allVersions,
+            defaultExtensions = 'vulkan',
+            addExtensions     = addExtensions,
+            removeExtensions  = removeExtensions,
+            prefixText        = prefixStrings + vkPrefixStrings,
+            protectFeature    = False,
+            apicall           = 'VKAPI_ATTR ',
+            apientry          = 'VKAPI_CALL ',
+            apientryp         = 'VKAPI_PTR *',
+            alignFuncParam    = 48,
+            helper_file_type  = 'typemap_helper_header')
+        ]
+
     # Options for mock ICD header
     genOpts['mock_icd.h'] = [
           MockICDOutputGenerator,