Update for Vulkan-Docs 1.1.120
diff --git a/include/vulkan/vulkan.hpp b/include/vulkan/vulkan.hpp
index f3a7df6..a3fbd2a 100644
--- a/include/vulkan/vulkan.hpp
+++ b/include/vulkan/vulkan.hpp
@@ -56,7 +56,7 @@
 # define VULKAN_HPP_ASSERT   assert
 #endif
 
-static_assert( VK_HEADER_VERSION ==  119 , "Wrong VK_HEADER_VERSION!" );
+static_assert( VK_HEADER_VERSION ==  120 , "Wrong VK_HEADER_VERSION!" );
 
 // 32-bit vulkan is not typesafe for handles, so don't allow copy constructors on this platform by default.
 // To enable this feature on 32-bit platforms please define VULKAN_HPP_TYPESAFE_CONVERSION
@@ -6017,7 +6017,8 @@
   enum class ValidationFeatureEnableEXT
   {
     eGpuAssisted = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
-    eGpuAssistedReserveBindingSlot = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT
+    eGpuAssistedReserveBindingSlot = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
+    eBestPractices = VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT
   };
 
   VULKAN_HPP_INLINE std::string to_string( ValidationFeatureEnableEXT value )
@@ -6026,6 +6027,7 @@
     {
       case ValidationFeatureEnableEXT::eGpuAssisted : return "GpuAssisted";
       case ValidationFeatureEnableEXT::eGpuAssistedReserveBindingSlot : return "GpuAssistedReserveBindingSlot";
+      case ValidationFeatureEnableEXT::eBestPractices : return "BestPractices";
       default: return "invalid";
     }
   }
@@ -23020,8 +23022,8 @@
     vk::ClearColorValue color;
     vk::ClearDepthStencilValue depthStencil;
 #else
-    Vkvk::ClearColorValue color;
-    Vkvk::ClearDepthStencilValue depthStencil;
+    VkClearColorValue color;
+    VkClearDepthStencilValue depthStencil;
 #endif  /*VULKAN_HPP_HAS_UNRESTRICTED_UNIONS*/
   };
 
@@ -42563,7 +42565,7 @@
     uint32_t value32;
     uint64_t value64;
     float valueFloat;
-    Vkvk::Bool32 valueBool;
+    VkBool32 valueBool;
     const char* valueString;
 #endif  /*VULKAN_HPP_HAS_UNRESTRICTED_UNIONS*/
   };
@@ -52291,49 +52293,6 @@
 
   union PipelineExecutableStatisticValueKHR
   {
-    PipelineExecutableStatisticValueKHR( vk::Bool32 b32_ = 0 )
-    {
-      b32 = b32_;
-    }
-
-    PipelineExecutableStatisticValueKHR( int64_t i64_ )
-    {
-      i64 = i64_;
-    }
-
-    PipelineExecutableStatisticValueKHR( uint64_t u64_ )
-    {
-      u64 = u64_;
-    }
-
-    PipelineExecutableStatisticValueKHR( double f64_ )
-    {
-      f64 = f64_;
-    }
-
-    PipelineExecutableStatisticValueKHR & setB32( vk::Bool32 b32_ )
-    {
-      b32 = b32_;
-      return *this;
-    }
-
-    PipelineExecutableStatisticValueKHR & setI64( int64_t i64_ )
-    {
-      i64 = i64_;
-      return *this;
-    }
-
-    PipelineExecutableStatisticValueKHR & setU64( uint64_t u64_ )
-    {
-      u64 = u64_;
-      return *this;
-    }
-
-    PipelineExecutableStatisticValueKHR & setF64( double f64_ )
-    {
-      f64 = f64_;
-      return *this;
-    }
     operator VkPipelineExecutableStatisticValueKHR const&() const
     {
       return *reinterpret_cast<const VkPipelineExecutableStatisticValueKHR*>(this);
@@ -52350,7 +52309,7 @@
     uint64_t u64;
     double f64;
 #else
-    Vkvk::Bool32 b32;
+    VkBool32 b32;
     int64_t i64;
     uint64_t u64;
     double f64;
diff --git a/include/vulkan/vulkan_android.h b/include/vulkan/vulkan_android.h
index 1861802..9b8d3e2 100644
--- a/include/vulkan/vulkan_android.h
+++ b/include/vulkan/vulkan_android.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_ANDROID_H_
 #define VULKAN_ANDROID_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_KHR_android_surface 1
 struct ANativeWindow;
diff --git a/include/vulkan/vulkan_core.h b/include/vulkan/vulkan_core.h
index e811beb..888674e 100644
--- a/include/vulkan/vulkan_core.h
+++ b/include/vulkan/vulkan_core.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_CORE_H_
 #define VULKAN_CORE_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_VERSION_1_0 1
 #include "vk_platform.h"
@@ -43,7 +44,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 119
+#define VK_HEADER_VERSION 120
 
 
 #define VK_NULL_HANDLE 0
@@ -8446,6 +8447,15 @@
 #define VK_NV_RAY_TRACING_EXTENSION_NAME  "VK_NV_ray_tracing"
 #define VK_SHADER_UNUSED_NV               (~0U)
 
+typedef enum VkAccelerationStructureTypeNV {
+    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
+    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
+    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV,
+    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1),
+    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
+} VkAccelerationStructureTypeNV;
+
 typedef enum VkRayTracingShaderGroupTypeNV {
     VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
     VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
@@ -8465,15 +8475,6 @@
     VK_GEOMETRY_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
 } VkGeometryTypeNV;
 
-typedef enum VkAccelerationStructureTypeNV {
-    VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
-    VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
-    VK_ACCELERATION_STRUCTURE_TYPE_BEGIN_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV,
-    VK_ACCELERATION_STRUCTURE_TYPE_END_RANGE_NV = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV,
-    VK_ACCELERATION_STRUCTURE_TYPE_RANGE_SIZE_NV = (VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV - VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV + 1),
-    VK_ACCELERATION_STRUCTURE_TYPE_MAX_ENUM_NV = 0x7FFFFFFF
-} VkAccelerationStructureTypeNV;
-
 typedef enum VkCopyAccelerationStructureModeNV {
     VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
     VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
@@ -9538,15 +9539,16 @@
 
 
 #define VK_EXT_validation_features 1
-#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 1
+#define VK_EXT_VALIDATION_FEATURES_SPEC_VERSION 2
 #define VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME "VK_EXT_validation_features"
 
 typedef enum VkValidationFeatureEnableEXT {
     VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0,
     VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1,
+    VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2,
     VK_VALIDATION_FEATURE_ENABLE_BEGIN_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT,
-    VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT,
-    VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1),
+    VK_VALIDATION_FEATURE_ENABLE_END_RANGE_EXT = VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT,
+    VK_VALIDATION_FEATURE_ENABLE_RANGE_SIZE_EXT = (VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT + 1),
     VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF
 } VkValidationFeatureEnableEXT;
 
diff --git a/include/vulkan/vulkan_fuchsia.h b/include/vulkan/vulkan_fuchsia.h
index 4c62a7c..81ebe55 100644
--- a/include/vulkan/vulkan_fuchsia.h
+++ b/include/vulkan/vulkan_fuchsia.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_FUCHSIA_H_
 #define VULKAN_FUCHSIA_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_FUCHSIA_imagepipe_surface 1
 #define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
diff --git a/include/vulkan/vulkan_ggp.h b/include/vulkan/vulkan_ggp.h
index 3d67c4b..fd30613 100644
--- a/include/vulkan/vulkan_ggp.h
+++ b/include/vulkan/vulkan_ggp.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_GGP_H_
 #define VULKAN_GGP_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_GGP_stream_descriptor_surface 1
 #define VK_GGP_STREAM_DESCRIPTOR_SURFACE_SPEC_VERSION 1
diff --git a/include/vulkan/vulkan_ios.h b/include/vulkan/vulkan_ios.h
index 1846df5..72ef1a8 100644
--- a/include/vulkan/vulkan_ios.h
+++ b/include/vulkan/vulkan_ios.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_IOS_H_
 #define VULKAN_IOS_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_MVK_ios_surface 1
 #define VK_MVK_IOS_SURFACE_SPEC_VERSION   2
diff --git a/include/vulkan/vulkan_macos.h b/include/vulkan/vulkan_macos.h
index dca623b..e6e5dea 100644
--- a/include/vulkan/vulkan_macos.h
+++ b/include/vulkan/vulkan_macos.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_MACOS_H_
 #define VULKAN_MACOS_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_MVK_macos_surface 1
 #define VK_MVK_MACOS_SURFACE_SPEC_VERSION 2
diff --git a/include/vulkan/vulkan_metal.h b/include/vulkan/vulkan_metal.h
index 1650523..3dec68c 100644
--- a/include/vulkan/vulkan_metal.h
+++ b/include/vulkan/vulkan_metal.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_METAL_H_
 #define VULKAN_METAL_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_EXT_metal_surface 1
 
diff --git a/include/vulkan/vulkan_vi.h b/include/vulkan/vulkan_vi.h
index 50aa27d..6fb66f9 100644
--- a/include/vulkan/vulkan_vi.h
+++ b/include/vulkan/vulkan_vi.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_VI_H_
 #define VULKAN_VI_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_NN_vi_surface 1
 #define VK_NN_VI_SURFACE_SPEC_VERSION     1
diff --git a/include/vulkan/vulkan_wayland.h b/include/vulkan/vulkan_wayland.h
index 12a5f04..599d05b 100644
--- a/include/vulkan/vulkan_wayland.h
+++ b/include/vulkan/vulkan_wayland.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_WAYLAND_H_
 #define VULKAN_WAYLAND_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_KHR_wayland_surface 1
 #define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
diff --git a/include/vulkan/vulkan_win32.h b/include/vulkan/vulkan_win32.h
index a61a7d8..7e6016e 100644
--- a/include/vulkan/vulkan_win32.h
+++ b/include/vulkan/vulkan_win32.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_WIN32_H_
 #define VULKAN_WIN32_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_KHR_win32_surface 1
 #define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
diff --git a/include/vulkan/vulkan_xcb.h b/include/vulkan/vulkan_xcb.h
index 7d6905d..4cc0bc0 100644
--- a/include/vulkan/vulkan_xcb.h
+++ b/include/vulkan/vulkan_xcb.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_XCB_H_
 #define VULKAN_XCB_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_KHR_xcb_surface 1
 #define VK_KHR_XCB_SURFACE_SPEC_VERSION   6
diff --git a/include/vulkan/vulkan_xlib.h b/include/vulkan/vulkan_xlib.h
index 7a05d29..ee2b48a 100644
--- a/include/vulkan/vulkan_xlib.h
+++ b/include/vulkan/vulkan_xlib.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_XLIB_H_
 #define VULKAN_XLIB_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_KHR_xlib_surface 1
 #define VK_KHR_XLIB_SURFACE_SPEC_VERSION  6
diff --git a/include/vulkan/vulkan_xlib_xrandr.h b/include/vulkan/vulkan_xlib_xrandr.h
index 3a20953..08c4fd7 100644
--- a/include/vulkan/vulkan_xlib_xrandr.h
+++ b/include/vulkan/vulkan_xlib_xrandr.h
@@ -1,10 +1,6 @@
 #ifndef VULKAN_XLIB_XRANDR_H_
 #define VULKAN_XLIB_XRANDR_H_ 1
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
 ** Copyright (c) 2015-2019 The Khronos Group Inc.
 **
@@ -27,6 +23,11 @@
 */
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 
 #define VK_EXT_acquire_xlib_display 1
 #define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
diff --git a/registry/cgenerator.py b/registry/cgenerator.py
index 7f2d9bc..75e03cf 100644
--- a/registry/cgenerator.py
+++ b/registry/cgenerator.py
@@ -134,15 +134,11 @@
                      'group', 'bitmask', 'funcpointer', 'struct']
     ALL_SECTIONS = TYPE_SECTIONS + ['commandPointer', 'command']
 
-    def __init__(self,
-                 errFile = sys.stderr,
-                 warnFile = sys.stderr,
-                 diagFile = sys.stdout):
-        OutputGenerator.__init__(self, errFile, warnFile, diagFile)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
         # Internal state - accumulators for different inner block text
         self.sections = {section: [] for section in self.ALL_SECTIONS}
         self.feature_not_empty = False
-        self.need_platform_include = False
         self.may_alias = None
 
     def beginFile(self, genOpts):
@@ -156,16 +152,19 @@
             write('#ifndef', headerSym, file=self.outFile)
             write('#define', headerSym, '1', file=self.outFile)
             self.newline()
-        write('#ifdef __cplusplus', file=self.outFile)
-        write('extern "C" {', file=self.outFile)
-        write('#endif', file=self.outFile)
-        self.newline()
 
         # User-supplied prefix text, if any (list of strings)
         if genOpts.prefixText:
             for s in genOpts.prefixText:
                 write(s, file=self.outFile)
 
+        # C++ extern wrapper - after prefix lines so they can add includes.
+        self.newline()
+        write('#ifdef __cplusplus', file=self.outFile)
+        write('extern "C" {', file=self.outFile)
+        write('#endif', file=self.outFile)
+        self.newline()
+
     def endFile(self):
         # C-specific
         # Finish C++ wrapper and multiple inclusion protection
@@ -206,14 +205,6 @@
                     self.newline()
                     write('#define', self.featureName, '1', file=self.outFile)
                     for section in self.TYPE_SECTIONS:
-                        # OpenXR:
-                        # If we need the explicit include of the external platform header,
-                        # put it right before the function pointer definitions
-                        if section == "funcpointer" and self.need_platform_include:
-                            write('// Include for OpenXR Platform-Specific Types', file=self.outFile)
-                            write('#include "openxr_platform.h"', file=self.outFile)
-                            self.newline()
-                            self.need_platform_include = False
                         contents = self.sections[section]
                         if contents:
                             write('\n'.join(contents), file=self.outFile)
@@ -292,27 +283,19 @@
     def genProtectString(self, protect_str):
         protect_if_str = ''
         protect_end_str = ''
-        protect_list = []
-        if protect_str:
-            if ',' in protect_str:
-                protect_list.extend(protect_str.split(","))
-                protect_def_str = ''
-                count = 0
-                for protect_define in protect_list:
-                    if count > 0:
-                        protect_def_str += ' &&'
-                    protect_def_str += ' defined(%s)' % protect_define
-                    count = count + 1
-                    count = count + 1
-                protect_if_str  = '#if'
-                protect_if_str += protect_def_str
-                protect_if_str += '\n'
-                protect_end_str  = '#endif //'
-                protect_end_str += protect_def_str
-                protect_end_str += '\n'
-            else:
-                protect_if_str += '#ifdef %s\n' % protect_str
-                protect_end_str += '#endif // %s\n' % protect_str
+        if not protect_str:
+            return (protect_if_str, protect_end_str)
+
+        if ',' in protect_str:
+            protect_list = protect_str.split(",")
+            protect_defs = ('defined(%s)' % d for d in protect_list)
+            protect_def_str = ' && '.join(protect_defs)
+            protect_if_str = '#if %s\n' % protect_def_str
+            protect_end_str = '#endif // %s\n' % protect_def_str
+        else:
+            protect_if_str = '#ifdef %s\n' % protect_str
+            protect_end_str = '#endif // %s\n' % protect_str
+
         return (protect_if_str, protect_end_str)
 
     def typeMayAlias(self, typeName):
@@ -326,11 +309,10 @@
                                  if data.elem.get('mayalias') == 'true')
 
             # Every type mentioned in some other type's parentstruct attribute.
-            self.may_alias.update(set(x for x in
-                                      [otherType.elem.get('parentstruct')
-                                       for _, otherType in self.registry.typedict.items()]
-                                      if x is not None
-                                      ))
+            parent_structs = (otherType.elem.get('parentstruct')
+                              for otherType in self.registry.typedict.values())
+            self.may_alias.update(set(x for x in parent_structs
+                                      if x is not None))
         return typeName in self.may_alias
 
     # Struct (e.g. C "struct" type) generation.
@@ -364,9 +346,7 @@
 
             body += ' ' + typeName + ' {\n'
 
-            targetLen = 0
-            for member in typeElem.findall('.//member'):
-                targetLen = max(targetLen, self.getCParamTypeLength(member))
+            targetLen = self.getMaxCParamTypeLength(typeinfo)
             for member in typeElem.findall('.//member'):
                 body += self.makeCParamDecl(member, targetLen + 4)
                 body += ';\n'
diff --git a/registry/conventions.py b/registry/conventions.py
index b37a494..8991b17 100644
--- a/registry/conventions.py
+++ b/registry/conventions.py
@@ -17,35 +17,96 @@
 # Base class for working-group-specific style conventions,
 # used in generation.
 
-from abc import ABCMeta, abstractmethod
+from enum import Enum
 
-ABC = ABCMeta('ABC', (object,), {})
+# Type categories that respond "False" to isStructAlwaysValid
+# basetype is home to typedefs like ..Bool32
+CATEGORIES_REQUIRING_VALIDATION = set(('handle',
+                                       'enum',
+                                       'bitmask',
+                                       'basetype',
+                                       None))
 
-class ConventionsBase(ABC):
+# These are basic C types pulled in via openxr_platform_defines.h
+TYPES_KNOWN_ALWAYS_VALID = set(('char',
+                                'float',
+                                'int8_t', 'uint8_t',
+                                'int32_t', 'uint32_t',
+                                'int64_t', 'uint64_t',
+                                'size_t',
+                                'uintptr_t',
+                                'int',
+                                ))
+
+
+class ProseListFormats(Enum):
+    """A connective, possibly with a quantifier."""
+    AND = 0
+    EACH_AND = 1
+    OR = 2
+    ANY_OR = 3
+
+    @classmethod
+    def from_string(cls, s):
+        if s == 'or':
+            return cls.OR
+        if s == 'and':
+            return cls.AND
+        return None
+
+    @property
+    def connective(self):
+        if self in (ProseListFormats.OR, ProseListFormats.ANY_OR):
+            return 'or'
+        return 'and'
+
+    def quantifier(self, n):
+        """Return the desired quantifier for a list of a given length."""
+        if self == ProseListFormats.ANY_OR:
+            if n > 1:
+                return 'any of '
+        elif self == ProseListFormats.EACH_AND:
+            if n > 2:
+                return 'each of '
+            if n == 2:
+                return 'both of '
+        return ''
+
+
+class ConventionsBase:
     """WG-specific conventions."""
 
-    @abstractmethod
+    def __init__(self):
+        self._command_prefix = None
+        self._type_prefix = None
+
     def formatExtension(self, name):
-        """Mark up a name as an extension for the spec."""
+        """Mark up a name as an extension for the spec.
+
+        Must implement."""
         raise NotImplementedError
 
     @property
-    @abstractmethod
     def null(self):
         """Preferred spelling of NULL."""
         raise NotImplementedError
 
-    def makeProseList(self, elements, connective='and'):
+    def makeProseList(self, elements, fmt=ProseListFormats.AND, with_verb=False, *args, **kwargs):
         """Make a (comma-separated) list for use in prose.
 
         Adds a connective (by default, 'and')
         before the last element if there are more than 1.
 
+        Adds the right one of "is" or "are" to the end if with_verb is true.
+
+        Optionally adds a quantifier (like 'any') before a list of 2 or more,
+        if specified by fmt.
+
         Override with a different method or different call to
         _implMakeProseList if you want to add a comma for two elements,
         or not use a serial comma.
         """
-        return self._implMakeProseList(elements, connective)
+        return self._implMakeProseList(elements, fmt, with_verb, *args, **kwargs)
 
     @property
     def struct_macro(self):
@@ -55,20 +116,20 @@
         """
         return 'sname:'
 
-    def makeStructName(self, name):
-        """Prepend the appropriate format macro for a structure to a structure type name.
-
-        Uses struct_macro, so just override that if you want to change behavior.
-        """
-        return self.struct_macro + name
-
     @property
     def external_macro(self):
         """Get the appropriate format macro for an external type like uint32_t.
 
         May override.
         """
-        return 'basetype:'
+        return 'code:'
+
+    def makeStructName(self, name):
+        """Prepend the appropriate format macro for a structure to a structure type name.
+
+        Uses struct_macro, so just override that if you want to change behavior.
+        """
+        return self.struct_macro + name
 
     def makeExternalTypeName(self, name):
         """Prepend the appropriate format macro for an external type like uint32_t to a type name.
@@ -77,7 +138,7 @@
         """
         return self.external_macro + name
 
-    def _implMakeProseList(self, elements, connective, comma_for_two_elts=False, serial_comma=True):
+    def _implMakeProseList(self, elements, fmt, with_verb, comma_for_two_elts=False, serial_comma=True):
         """Internal-use implementation to make a (comma-separated) list for use in prose.
 
         Adds a connective (by default, 'and')
@@ -85,48 +146,171 @@
         and only includes commas if there are more than 2
         (if comma_for_two_elts is False).
 
+        Adds the right one of "is" or "are" to the end if with_verb is true.
+
+        Optionally adds a quantifier (like 'any') before a list of 2 or more,
+        if specified by fmt.
+
         Don't edit these defaults, override self.makeProseList().
         """
         assert(serial_comma)  # didn't implement what we didn't need
+        if isinstance(fmt, str):
+            fmt = ProseListFormats.from_string(fmt)
+
         my_elts = list(elements)
         if len(my_elts) > 1:
-            my_elts[-1] = '{} {}'.format(connective, my_elts[-1])
+            my_elts[-1] = '{} {}'.format(fmt.connective, my_elts[-1])
 
         if not comma_for_two_elts and len(my_elts) <= 2:
-            return ' '.join(my_elts)
-        return ', '.join(my_elts)
+            prose = ' '.join(my_elts)
+        else:
+            prose = ', '.join(my_elts)
+
+        quantifier = fmt.quantifier(len(my_elts))
+
+        parts = [quantifier, prose]
+
+        if with_verb:
+            if len(my_elts) > 1:
+                parts.append(' are')
+            else:
+                parts.append(' is')
+        return ''.join(parts)
 
     @property
-    @abstractmethod
     def file_suffix(self):
         """Return suffix of generated Asciidoctor files"""
         raise NotImplementedError
 
-    @abstractmethod
-    def api_name(self, spectype = None):
-        """Return API name"""
+    def api_name(self, spectype=None):
+        """Return API or specification name for citations in ref pages.
+
+        spectype is the spec this refpage is for.
+        'api' (the default value) is the main API Specification.
+        If an unrecognized spectype is given, returns None.
+
+        Must implement."""
         raise NotImplementedError
 
+    def should_insert_may_alias_macro(self, genOpts):
+        """Return true if we should insert a "may alias" macro in this file.
+
+        Only used by OpenXR right now."""
+        return False
+
     @property
-    @abstractmethod
+    def command_prefix(self):
+        """Return the expected prefix of commands/functions.
+
+        Implemented in terms of api_prefix."""
+        if not self._command_prefix:
+            self._command_prefix = self.api_prefix[:].replace('_', '').lower()
+        return self._command_prefix
+
+    @property
+    def type_prefix(self):
+        """Return the expected prefix of type names.
+
+        Implemented in terms of command_prefix (and in turn, api_prefix)."""
+        if not self._type_prefix:
+            self._type_prefix = ''.join(
+                (self.command_prefix[0:1].upper(), self.command_prefix[1:]))
+        return self._type_prefix
+
+    @property
     def api_prefix(self):
-        """Return API token prefix"""
+        """Return API token prefix.
+
+        Typically two uppercase letters followed by an underscore.
+
+        Must implement."""
         raise NotImplementedError
 
     @property
-    @abstractmethod
     def api_version_prefix(self):
-        """Return API core version token prefix"""
-        raise NotImplementedError
+        """Return API core version token prefix.
+
+        Implemented in terms of api_prefix.
+
+        May override."""
+        return self.api_prefix + 'VERSION_'
 
     @property
-    @abstractmethod
     def KHR_prefix(self):
-        """Return extension name prefix for KHR extensions"""
-        raise NotImplementedError
+        """Return extension name prefix for KHR extensions.
+
+        Implemented in terms of api_prefix.
+
+        May override."""
+        return self.api_prefix + 'KHR_'
 
     @property
-    @abstractmethod
     def EXT_prefix(self):
-        """Return extension name prefix for EXT extensions"""
-        raise NotImplementedError
+        """Return extension name prefix for EXT extensions.
+
+        Implemented in terms of api_prefix.
+
+        May override."""
+        return self.api_prefix + 'EXT_'
+
+    def writeFeature(self, featureExtraProtect, filename):
+        """Return True if OutputGenerator.endFeature should write this feature.
+
+        Defaults to always True.
+        Used in COutputGenerator.
+
+        May override."""
+        return True
+
+    def requires_error_validation(self, return_type):
+        """Return True if the return_type element is an API result code
+        requiring error validation.
+
+        Defaults to always False.
+
+        May override."""
+        return False
+
+    @property
+    def required_errors(self):
+        """Return a list of required error codes for validation.
+
+        Defaults to an empty list.
+
+        May override."""
+        return []
+
+    def is_voidpointer_alias(self, tag, text, tail):
+        """Return True if the declaration components (tag,text,tail) of an
+        element represents a void * type.
+
+        Defaults to a reasonable implementation.
+
+        May override."""
+        return tag == 'type' and text == 'void' and tail.startswith('*')
+
+    def make_voidpointer_alias(self, tail):
+        """Reformat a void * declaration to include the API alias macro.
+
+        Defaults to a no-op.
+
+        Must override if you actually want to use this feature in your project."""
+        return tail
+
+    def category_requires_validation(self, category):
+        """Return True if the given type 'category' always requires validation.
+
+        Defaults to a reasonable implementation.
+
+        May override."""
+        return category in CATEGORIES_REQUIRING_VALIDATION
+
+    def type_always_valid(self, typename):
+        """Return True if the given type name is always valid (never requires validation).
+
+        This is for things like integers.
+
+        Defaults to a reasonable implementation.
+
+        May override."""
+        return typename in TYPES_KNOWN_ALWAYS_VALID
diff --git a/registry/generator.py b/registry/generator.py
index f62b71f..8573655 100644
--- a/registry/generator.py
+++ b/registry/generator.py
@@ -18,17 +18,20 @@
 
 import io
 import os
-import re
 import pdb
+import re
 import sys
 try:
     from pathlib import Path
 except ImportError:
     from pathlib2 import Path
 
-def write( *args, **kwargs ):
-    file = kwargs.pop('file',sys.stdout)
-    end = kwargs.pop('end','\n')
+from spec_tools.util import getElemName, getElemType
+
+
+def write(*args, **kwargs):
+    file = kwargs.pop('file', sys.stdout)
+    end = kwargs.pop('end', '\n')
     file.write(' '.join(str(arg) for arg in args))
     file.write(end)
 
@@ -83,9 +86,10 @@
 #   then by version number (for features)
 #   then by extension number (for extensions)
 def regSortFeatures(featureList):
-    featureList.sort(key = regSortExtensionNumberKey)
-    featureList.sort(key = regSortFeatureVersionKey)
-    featureList.sort(key = regSortCategoryKey)
+    featureList.sort(key=regSortExtensionNumberKey)
+    featureList.sort(key=regSortFeatureVersionKey)
+    featureList.sort(key=regSortCategoryKey)
+
 
 # GeneratorOptions - base class for options used during header production
 # These options are target language independent, and used by
@@ -125,18 +129,18 @@
     """Represents options during header production from an API registry"""
 
     def __init__(self,
-                 conventions = None,
-                 filename = None,
-                 directory = '.',
-                 apiname = None,
-                 profile = None,
-                 versions = '.*',
-                 emitversions = '.*',
-                 defaultExtensions = None,
-                 addExtensions = None,
-                 removeExtensions = None,
-                 emitExtensions = None,
-                 sortProcedure = regSortFeatures):
+                 conventions=None,
+                 filename=None,
+                 directory='.',
+                 apiname=None,
+                 profile=None,
+                 versions='.*',
+                 emitversions='.*',
+                 defaultExtensions=None,
+                 addExtensions=None,
+                 removeExtensions=None,
+                 emitExtensions=None,
+                 sortProcedure=regSortFeatures):
         self.conventions       = conventions
         self.filename          = filename
         self.directory         = directory
@@ -205,19 +209,19 @@
 
     # categoryToPath - map XML 'category' to include file directory name
     categoryToPath = {
-        'bitmask'      : 'flags',
-        'enum'         : 'enums',
-        'funcpointer'  : 'funcpointers',
-        'handle'       : 'handles',
-        'define'       : 'defines',
-        'basetype'     : 'basetypes',
+        'bitmask': 'flags',
+        'enum': 'enums',
+        'funcpointer': 'funcpointers',
+        'handle': 'handles',
+        'define': 'defines',
+        'basetype': 'basetypes',
     }
 
     # Constructor
     def __init__(self,
-                 errFile = sys.stderr,
-                 warnFile = sys.stderr,
-                 diagFile = sys.stdout):
+                 errFile=sys.stderr,
+                 warnFile=sys.stderr,
+                 diagFile=sys.stdout):
         self.outFile = None
         self.errFile = errFile
         self.warnFile = warnFile
@@ -227,7 +231,7 @@
         self.genOpts = None
         self.registry = None
         # Used for extension enum value generation
-        self.extBase      = 1000000000
+        self.extBase = 1000000000
         self.extBlockSize = 1000
         self.madeDirs = {}
 
@@ -295,21 +299,21 @@
             bitpos = int(value, 0)
             numVal = 1 << bitpos
             value = '0x%08x' % numVal
-            if( bitpos >= 32 ):
+            if bitpos >= 32:
                 value = value + 'ULL'
             self.logMsg('diag', 'Enum', name, '-> bitpos [', numVal, ',', value, ']')
             return [numVal, value]
         if 'offset' in elem.keys():
             # Obtain values in the mapping from the attributes
             enumNegative = False
-            offset = int(elem.get('offset'),0)
-            extnumber = int(elem.get('extnumber'),0)
+            offset = int(elem.get('offset'), 0)
+            extnumber = int(elem.get('extnumber'), 0)
             extends = elem.get('extends')
             if 'dir' in elem.keys():
                 enumNegative = True
             self.logMsg('diag', 'Enum', name, 'offset =', offset,
-                'extnumber =', extnumber, 'extends =', extends,
-                'enumNegative =', enumNegative)
+                        'extnumber =', extnumber, 'extends =', extends,
+                        'enumNegative =', enumNegative)
             # Now determine the actual enumerant value, as defined
             # in the "Layers and Extensions" appendix of the spec.
             numVal = self.extBase + (extnumber - 1) * self.extBlockSize + offset
@@ -346,7 +350,7 @@
                 # happens when defining the same enum conditionally in
                 # several extension blocks.
                 if (strVal2 == strVal or (numVal is not None and
-                    numVal == numVal2)):
+                                          numVal == numVal2)):
                     True
                     # self.logMsg('info', 'checkDuplicateEnums: Duplicate enum (' + name +
                     #             ') found with the same value:' + strVal)
@@ -364,14 +368,14 @@
 
                 try:
                     self.logMsg('warn', 'Two enums found with the same value: '
-                             + name + ' = ' + name2.get('name') + ' = ' + strVal)
+                                + name + ' = ' + name2.get('name') + ' = ' + strVal)
                 except:
                     pdb.set_trace()
 
             # Track this enum to detect followon duplicates
-            nameMap[name] = [ elem, numVal, strVal ]
+            nameMap[name] = [elem, numVal, strVal]
             if numVal is not None:
-                valueMap[numVal] = [ elem, numVal, strVal ]
+                valueMap[numVal] = [elem, numVal, strVal]
 
             # Add this enum to the list
             stripped.append(elem)
@@ -385,7 +389,7 @@
         groupElem = groupinfo.elem
 
         if self.genOpts.conventions.constFlagBits and groupElem.get('type') == 'bitmask':
-            return self.buildEnumCDecl_Bitmask( groupinfo, groupName)
+            return self.buildEnumCDecl_Bitmask(groupinfo, groupName)
         else:
             return self.buildEnumCDecl_Enum(expand, groupinfo, groupName)
 
@@ -406,7 +410,7 @@
             # Should catch exceptions here for more complex constructs. Not yet.
             (_, strVal) = self.enumToValue(elem, True)
             name = elem.get('name')
-            body += "static const " + flagTypeName + " " + name + " = " + strVal + ";\n"
+            body += "static const {} {} = {};\n".format(flagTypeName, name, strVal)
 
         # Postfix
 
@@ -418,17 +422,17 @@
 
         # Break the group name into prefix and suffix portions for range
         # enum generation
-        expandName = re.sub(r'([0-9a-z_])([A-Z0-9])',r'\1_\2',groupName).upper()
+        expandName = re.sub(r'([0-9a-z_])([A-Z0-9])', r'\1_\2', groupName).upper()
         expandPrefix = expandName
         expandSuffix = ''
-        expandSuffixMatch = re.search(r'[A-Z][A-Z]+$',groupName)
+        expandSuffixMatch = re.search(r'[A-Z][A-Z]+$', groupName)
         if expandSuffixMatch:
             expandSuffix = '_' + expandSuffixMatch.group()
             # Strip off the suffix from the prefix
             expandPrefix = expandName.rsplit(expandSuffix, 1)[0]
 
         # Prefix
-        body = "typedef enum " + groupName + " {\n"
+        body = ["typedef enum %s {" % groupName]
 
         # @@ Should use the type="bitmask" attribute instead
         isEnum = ('FLAG_BITS' not in expandPrefix)
@@ -450,22 +454,22 @@
         # them following the numeric values, to allow for aliases.
         # NOTE: this doesn't do a topological sort yet, so aliases of
         # aliases can still get in the wrong order.
-        aliasText = ""
+        aliasText = []
 
         for elem in enums:
             # Convert the value to an integer and use that to track min/max.
             # Values of form -(number) are accepted but nothing more complex.
             # Should catch exceptions here for more complex constructs. Not yet.
-            (numVal,strVal) = self.enumToValue(elem, True)
+            (numVal, strVal) = self.enumToValue(elem, True)
             name = elem.get('name')
 
             # Extension enumerants are only included if they are required
             if self.isEnumRequired(elem):
-                decl = "    " + name + " = " + strVal + ",\n"
+                decl = "    {} = {},".format(name, strVal)
                 if numVal is not None:
-                    body += decl
+                    body.append(decl)
                 else:
-                    aliasText += decl
+                    aliasText.append(decl)
 
             # Don't track min/max for non-numbers (numVal is None)
             if isEnum and numVal is not None and elem.get('extends') is None:
@@ -480,20 +484,21 @@
                     maxValue = numVal
 
         # Now append the non-numeric enumerant values
-        body += aliasText
+        body.extend(aliasText)
 
         # Generate min/max value tokens and a range-padding enum. Need some
         # additional padding to generate correct names...
         if isEnum and expand:
-            body += "    " + expandPrefix + "_BEGIN_RANGE" + expandSuffix + " = " + minName + ",\n"
-            body += "    " + expandPrefix + "_END_RANGE" + expandSuffix + " = " + maxName + ",\n"
-            body += "    " + expandPrefix + "_RANGE_SIZE" + expandSuffix + " = (" + maxName + " - " + minName + " + 1),\n"
+            body.extend(("    {}_BEGIN_RANGE{} = {},".format(expandPrefix, expandSuffix, minName),
+                         "    {}_END_RANGE{} = {},".format(
+                             expandPrefix, expandSuffix, maxName),
+                         "    {}_RANGE_SIZE{} = ({} - {} + 1),".format(expandPrefix, expandSuffix, maxName, minName)))
 
-        # Always generate this to make sure the enumerated type is 32 bits
-        body += "    " + expandPrefix + "_MAX_ENUM" + expandSuffix + " = 0x7FFFFFFF\n"
+        body.append("    {}_MAX_ENUM{} = 0x7FFFFFFF".format(
+            expandPrefix, expandSuffix))
 
         # Postfix
-        body += "} " + groupName + ";"
+        body.append("} %s;" % groupName)
 
         # Determine appropriate section for this declaration
         if groupElem.get('type') == 'bitmask':
@@ -501,7 +506,7 @@
         else:
             section = 'group'
 
-        return (section, body)
+        return (section, '\n'.join(body))
 
     def makeDir(self, path):
         self.logMsg('diag', 'OutputGenerator::makeDir(' + path + ')')
@@ -514,6 +519,10 @@
 
     def beginFile(self, genOpts):
         self.genOpts = genOpts
+        self.should_insert_may_alias_macro = \
+            self.genOpts.conventions.should_insert_may_alias_macro(self.genOpts)
+
+        self.conventions = genOpts.conventions
 
         # Open specified output file. Not done in constructor since a
         # Generator can be used without writing to a file.
@@ -603,13 +612,14 @@
     # aligncol - if non-zero, attempt to align the nested <name> element
     #   at this column
     def makeCParamDecl(self, param, aligncol):
-        paramdecl = '    ' + noneStr(param.text)
+        indent = '    '
+        paramdecl = indent + noneStr(param.text)
         for elem in param:
             text = noneStr(elem.text)
             tail = noneStr(elem.tail)
 
-            if self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
-                # OpenXR-specific macro insertion
+            if self.should_insert_may_alias_macro and self.genOpts.conventions.is_voidpointer_alias(elem.tag, text, tail):
+                # OpenXR-specific macro insertion - but not in apiinc for the spec
                 tail = self.genOpts.conventions.make_voidpointer_alias(tail)
             if elem.tag == 'name' and aligncol > 0:
                 self.logMsg('diag', 'Aligning parameter', elem.text, 'to column', self.genOpts.alignFuncParam)
@@ -619,17 +629,22 @@
                 # This works around a problem where very long type names -
                 # longer than the alignment column - would run into the tail
                 # text.
-                paramdecl = paramdecl.ljust(aligncol-1) + ' '
+                paramdecl = paramdecl.ljust(aligncol - 1) + ' '
                 newLen = len(paramdecl)
                 self.logMsg('diag', 'Adjust length of parameter decl from', oldLen, 'to', newLen, ':', paramdecl)
             paramdecl += text + tail
+        if aligncol == 0:
+            # Squeeze out multiple spaces other than the identation
+            paramdecl = indent + ' '.join(paramdecl.split())
         return paramdecl
 
-    # getCParamTypeLength - return the length of the type field is an indented, formatted
-    # declaration for a <param> or <member> block (e.g. function parameter
-    # or structure/union member).
+    # getCParamTypeLength - return the length of the type field in an
+    # indented, formatted declaration for a <param> or <member> block (e.g.
+    # function parameter or structure/union member). This relies on the
+    # presence of the <name> tag; if not present, return zero.
     # param - Element (<param> or <member>) to identify
     def getCParamTypeLength(self, param):
+        newLen = 0
         paramdecl = '    ' + noneStr(param.text)
         for elem in param:
             text = noneStr(elem.text)
@@ -646,17 +661,106 @@
 
         return newLen
 
+    def getMaxCParamTypeLength(self, info):
+        """Return the length of the longest type field for a member/parameter.
+
+        info - TypeInfo or CommandInfo.
+        """
+        lengths = (self.getCParamTypeLength(member)
+                   for member in info.getMembers())
+        return max(lengths)
+
+    def getHandleParent(self, typename):
+        """Get the parent of a handle object."""
+        info = self.registry.typedict.get(typename)
+        if info is None:
+            return None
+
+        elem = info.elem
+        if elem is not None:
+            return elem.get('parent')
+
+        return None
+
+    def iterateHandleAncestors(self, typename):
+        """Iterate through the ancestors of a handle type."""
+        current = self.getHandleParent(typename)
+        while current is not None:
+            yield current
+            current = self.getHandleParent(current)
+
+    def getHandleAncestors(self, typename):
+        """Get the ancestors of a handle object."""
+        return list(self.iterateHandleAncestors(typename))
+
+    def getTypeCategory(self, typename):
+        """Get the category of a type."""
+        info = self.registry.typedict.get(typename)
+        if info is None:
+            return None
+
+        elem = info.elem
+        if elem is not None:
+            return elem.get('category')
+        return None
+
+    def isStructAlwaysValid(self, structname):
+        """Try to do check if a structure is always considered valid (i.e. there's no rules to its acceptance)."""
+        # A conventions object is required for this call.
+        if not self.conventions:
+            raise RuntimeError("To use isStructAlwaysValid, be sure your options include a Conventions object.")
+
+        if self.conventions.type_always_valid(structname):
+            return True
+
+        category = self.getTypeCategory(structname)
+        if self.conventions.category_requires_validation(category):
+            return False
+
+        info = self.registry.typedict.get(structname)
+        assert(info is not None)
+
+        members = info.getMembers()
+
+        for member in members:
+            member_name = getElemName(member)
+            if member_name in (self.conventions.structtype_member_name,
+                               self.conventions.nextpointer_member_name):
+                return False
+
+            if member.get('noautovalidity'):
+                return False
+
+            member_type = getElemType(member)
+
+            if member_type in ('void', 'char') or self.paramIsArray(member) or self.paramIsPointer(member):
+                return False
+
+            if self.conventions.type_always_valid(member_type):
+                continue
+
+            member_category = self.getTypeCategory(member_type)
+
+            if self.conventions.category_requires_validation(member_category):
+                return False
+
+            if member_category in ('struct', 'union'):
+                if self.isStructAlwaysValid(member_type) is False:
+                    return False
+
+        return True
+
     # isEnumRequired(elem) - return True if this <enum> element is
     # required, False otherwise
     # elem - <enum> element to test
     def isEnumRequired(self, elem):
         required = elem.get('required') is not None
         self.logMsg('diag', 'isEnumRequired:', elem.get('name'),
-            '->', required)
+                    '->', required)
         return required
 
-        #@@@ This code is overridden by equivalent code now run in
-        #@@@ Registry.generateFeature
+        # @@@ This code is overridden by equivalent code now run in
+        # @@@ Registry.generateFeature
 
         required = False
 
@@ -707,6 +811,12 @@
             else:
                 pdecl += text + tail
                 tdecl += text + tail
+
+        if self.genOpts.alignFuncParam == 0:
+            # Squeeze out multiple spaces - there is no indentation
+            pdecl = ' '.join(pdecl.split())
+            tdecl = ' '.join(tdecl.split())
+
         # Now add the parameter declaration list, which is identical
         # for prototypes and typedefs. Concatenate all the text from
         # a <param> node without the tags. No tree walking required
@@ -732,7 +842,7 @@
         else:
             paramdecl += 'void'
         paramdecl += ");"
-        return [ pdecl + indentdecl, tdecl + paramdecl ]
+        return [pdecl + indentdecl, tdecl + paramdecl]
 
     def newline(self):
         write('', file=self.outFile)
diff --git a/registry/genvk.py b/registry/genvk.py
index 6355f86..84cad3c 100644
--- a/registry/genvk.py
+++ b/registry/genvk.py
@@ -48,12 +48,14 @@
         write(msg, endTime - startTime, file=sys.stderr)
         startTime = None
 
-# Turn a list of strings into a regexp string matching exactly those strings
-def makeREstring(list, default = None):
-    if len(list) > 0 or default is None:
-        return '^(' + '|'.join(list) + ')$'
-    else:
-        return default
+
+def makeREstring(strings, default=None, strings_are_regex=False):
+    """Turn a list of strings into a regexp string matching exactly those strings."""
+    if strings or default is None:
+        if not strings_are_regex:
+            strings = (re.escape(s) for s in strings)
+        return '^(' + '|'.join(strings) + ')$'
+    return default
 
 # Returns a directory of [ generator function, generator options ] indexed
 # by specified short names. The generator options incorporate the following
@@ -275,8 +277,10 @@
 
         allPlatformExtensions += platform[1]
 
-        addPlatformExtensionsRE = makeREstring(platform[1] + platform[2])
-        emitPlatformExtensionsRE = makeREstring(platform[1])
+        addPlatformExtensionsRE = makeREstring(
+            platform[1] + platform[2], strings_are_regex=True)
+        emitPlatformExtensionsRE = makeREstring(
+            platform[1], strings_are_regex=True)
 
         opts = CGeneratorOptions(
             conventions       = conventions,
@@ -312,7 +316,8 @@
     # It removes all platform extensions (from the platform headers options
     # constructed above) as well as any explicitly specified removals.
 
-    removeExtensionsPat = makeREstring(allPlatformExtensions + removeExtensions, None)
+    removeExtensionsPat = makeREstring(
+        allPlatformExtensions + removeExtensions, None, strings_are_regex=True)
 
     genOpts['vulkan_core.h'] = [
           COutputGenerator,
@@ -533,7 +538,8 @@
     if args.debug:
         pdb.run('genTarget(args)')
     elif args.profile:
-        import cProfile, pstats
+        import cProfile
+        import pstats
         cProfile.run('genTarget(args)', 'profile.txt')
         p = pstats.Stats('profile.txt')
         p.strip_dirs().sort_stats('time').print_stats(50)
diff --git a/registry/reg.py b/registry/reg.py
index 982c04c..fb30ed8 100644
--- a/registry/reg.py
+++ b/registry/reg.py
@@ -104,8 +104,8 @@
         # be different when redefining the same interface in different feature
         # and/or extension blocks.
         for key in selfKeys:
-            if (key != 'extname' and key != 'extnumber' and
-                (self.elem.get(key) != info.elem.get(key))):
+            if key not in ('extname', 'extnumber') and \
+                    (self.elem.get(key) != info.elem.get(key)):
                 return False
 
         return True
@@ -118,6 +118,10 @@
         BaseInfo.__init__(self, elem)
         self.additionalValidity = []
         self.removedValidity = []
+
+    def getMembers(self):
+        return self.elem.findall('member')
+
     def resetState(self):
         BaseInfo.resetState(self)
         self.additionalValidity = []
@@ -148,6 +152,10 @@
         BaseInfo.__init__(self, elem)
         self.additionalValidity = []
         self.removedValidity = []
+
+    def getParams(self):
+        return self.elem.findall('param')
+
     def resetState(self):
         BaseInfo.resetState(self)
         self.additionalValidity = []
@@ -251,6 +259,7 @@
         self.emitFeatures = False
         self.breakPat     = None
         # self.breakPat     = re.compile('VkFenceImportFlagBits.*')
+        self.filename     = None
 
     def loadElementTree(self, tree):
         """Load ElementTree into a Registry object and parse it"""
@@ -259,6 +268,7 @@
 
     def loadFile(self, file):
         """Load an API registry XML file into a Registry object and parse it"""
+        self.filename = file
         self.tree = etree.parse(file)
         self.parseTree()
 
@@ -450,7 +460,11 @@
                             gi.elem.append(enum)
                             # Remove element from parent <require> tag
                             # This should be a no-op in lxml.etree
-                            elem.remove(enum)
+                            try:
+                                elem.remove(enum)
+                            except ValueError:
+                                # Must be lxml.etree
+                                pass
                         else:
                             self.gen.logMsg('warn', 'NO matching group',
                                 groupName, 'for enum', enum.get('name'), 'found.')
@@ -500,7 +514,11 @@
                             gi.elem.append(enum)
                             # Remove element from parent <require> tag
                             # This should be a no-op in lxml.etree
-                            elem.remove(enum)
+                            try:
+                                elem.remove(enum)
+                            except ValueError:
+                                # Must be lxml.etree
+                                pass
                         else:
                             self.gen.logMsg('warn', 'NO matching group',
                                 groupName, 'for enum', enum.get('name'), 'found.')
diff --git a/registry/validusage.json b/registry/validusage.json
index 8a2ea3e..9240390 100644
--- a/registry/validusage.json
+++ b/registry/validusage.json
@@ -1,9 +1,9 @@
 {
   "version info": {
     "schema version": 2,
-    "api version": "1.1.119",
-    "comment": "from git branch: github-master commit: 5a1c484b7e65eb7d83b160f8c92b0cfd77ddbd53",
-    "date": "2019-08-12 06:32:53Z"
+    "api version": "1.1.120",
+    "comment": "from git branch: github-master commit: 521e98405f8587ce6506811125c001f1eda26314",
+    "date": "2019-08-17 22:33:44Z"
   },
   "validation": {
     "vkGetInstanceProcAddr": {
@@ -717,6 +717,10 @@
         {
           "vuid": "VUID-vkAllocateCommandBuffers-pCommandBuffers-parameter",
           "text": " <code>pCommandBuffers</code> <strong class=\"purple\">must</strong> be a valid pointer to an array of <code>pAllocateInfo</code>::commandBufferCount <code>VkCommandBuffer</code> handles"
+        },
+        {
+          "vuid": "VUID-vkAllocateCommandBuffers-pAllocateInfo::commandBufferCount-arraylength",
+          "text": " The value referenced by <code>pAllocateInfo</code>::<code>commandBufferCount</code> <strong class=\"purple\">must</strong> be greater than <code>0</code>"
         }
       ]
     },
@@ -863,6 +867,14 @@
           "text": " If the <a href=\"#features-inheritedQueries\">inherited queries</a> feature is enabled, <code>queryFlags</code> <strong class=\"purple\">must</strong> be a valid combination of <a href=\"#VkQueryControlFlagBits\">VkQueryControlFlagBits</a> values"
         },
         {
+          "vuid": "VUID-VkCommandBufferInheritanceInfo-queryFlags-02788",
+          "text": " If the <a href=\"#features-inheritedQueries\">inherited queries</a> feature is not enabled, <code>queryFlags</code> <strong class=\"purple\">must</strong> be <code>0</code>"
+        },
+        {
+          "vuid": "VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789",
+          "text": " If the <a href=\"#features-pipelineStatisticsQuery\">pipeline statistics queries</a> feature is enabled, <code>pipelineStatistics</code> <strong class=\"purple\">must</strong> be a valid combination of <a href=\"#VkQueryPipelineStatisticFlagBits\">VkQueryPipelineStatisticFlagBits</a> values"
+        },
+        {
           "vuid": "VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058",
           "text": " If the <a href=\"#features-pipelineStatisticsQuery\">pipeline statistics queries</a> feature is not enabled, <code>pipelineStatistics</code> <strong class=\"purple\">must</strong> be <code>0</code>"
         },
@@ -954,7 +966,7 @@
         },
         {
           "vuid": "VUID-vkQueueSubmit-pWaitSemaphores-00068",
-          "text": " When a semaphore unsignal operation defined by any element of the <code>pWaitSemaphores</code> member of any element of <code>pSubmits</code> executes on <code>queue</code>, no other queue <strong class=\"purple\">must</strong> be waiting on the same semaphore."
+          "text": " When a semaphore unsignal operation defined by any element of the <code>pWaitSemaphores</code> member of any element of <code>pSubmits</code> executes on <code>queue</code>, there <strong class=\"purple\">must</strong> be no other queues waiting on the same semaphore."
         },
         {
           "vuid": "VUID-vkQueueSubmit-pWaitSemaphores-00069",
@@ -6216,7 +6228,7 @@
       "(VK_KHR_pipeline_executable_properties)": [
         {
           "vuid": "VUID-VkPipelineExecutableInfoKHR-executableIndex-03275",
-          "text": " <code>executableIndex</code> <strong class=\"purple\">must</strong> be less than or equal to the number of executables associated with <code>pipeline</code> as returned in the <code>pExecutableCount</code> parameter of <code>vkGetPipelineExecutablePropertiesKHR</code>."
+          "text": " <code>executableIndex</code> <strong class=\"purple\">must</strong> be less than the number of executables associated with <code>pipeline</code> as returned in the <code>pExecutableCount</code> parameter of <code>vkGetPipelineExecutablePropertiesKHR</code>."
         },
         {
           "vuid": "VUID-VkPipelineExecutableInfoKHR-sType-sType",
@@ -6288,11 +6300,11 @@
         },
         {
           "vuid": "VUID-VkPipelineExecutableInternalRepresentationKHR-name-parameter",
-          "text": " Any given element of <code>name</code> <strong class=\"purple\">must</strong> be a valid"
+          "text": " <code>name</code> <strong class=\"purple\">must</strong> be a null-terminated UTF-8 string whose length is less than or equal to VK_MAX_DESCRIPTION_SIZE"
         },
         {
           "vuid": "VUID-VkPipelineExecutableInternalRepresentationKHR-description-parameter",
-          "text": " Any given element of <code>description</code> <strong class=\"purple\">must</strong> be a valid"
+          "text": " <code>description</code> <strong class=\"purple\">must</strong> be a null-terminated UTF-8 string whose length is less than or equal to VK_MAX_DESCRIPTION_SIZE"
         },
         {
           "vuid": "VUID-VkPipelineExecutableInternalRepresentationKHR-pData-parameter",
@@ -6339,8 +6351,8 @@
           "text": " <code>sType</code> <strong class=\"purple\">must</strong> be <code>VK_STRUCTURE_TYPE_PIPELINE_COMPILER_CONTROL_CREATE_INFO_AMD</code>"
         },
         {
-          "vuid": "VUID-VkPipelineCompilerControlCreateInfoAMD-compilerControlFlags-parameter",
-          "text": " <code>compilerControlFlags</code> <strong class=\"purple\">must</strong> be a valid combination of <a href=\"#VkPipelineCompilerControlFlagBitsAMD\">VkPipelineCompilerControlFlagBitsAMD</a> values"
+          "vuid": "VUID-VkPipelineCompilerControlCreateInfoAMD-compilerControlFlags-zerobitmask",
+          "text": " <code>compilerControlFlags</code> <strong class=\"purple\">must</strong> be <code>0</code>"
         }
       ]
     },
@@ -9256,7 +9268,7 @@
         },
         {
           "vuid": "VUID-VkImageViewHandleInfoNVX-imageView-02656",
-          "text": "    If descriptorType is <code>VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE</code> or    <code>VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER</code>, the image that    <code>imageView</code> was created from <strong class=\"purple\">must</strong> have been created with the    <code>VK_IMAGE_USAGE_SAMPLED_BIT</code> usage bit set"
+          "text": " If descriptorType is <code>VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE</code> or <code>VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER</code>, the image that <code>imageView</code> was created from <strong class=\"purple\">must</strong> have been created with the <code>VK_IMAGE_USAGE_SAMPLED_BIT</code> usage bit set"
         },
         {
           "vuid": "VUID-VkImageViewHandleInfoNVX-imageView-02657",
@@ -11523,6 +11535,10 @@
         {
           "vuid": "VUID-vkAllocateDescriptorSets-pDescriptorSets-parameter",
           "text": " <code>pDescriptorSets</code> <strong class=\"purple\">must</strong> be a valid pointer to an array of <code>pAllocateInfo</code>::descriptorSetCount <code>VkDescriptorSet</code> handles"
+        },
+        {
+          "vuid": "VUID-vkAllocateDescriptorSets-pAllocateInfo::descriptorSetCount-arraylength",
+          "text": " The value referenced by <code>pAllocateInfo</code>::<code>descriptorSetCount</code> <strong class=\"purple\">must</strong> be greater than <code>0</code>"
         }
       ]
     },
@@ -20578,7 +20594,7 @@
         },
         {
           "vuid": "VUID-vkQueueBindSparse-pWaitSemaphores-01116",
-          "text": " When a semaphore unsignal operation defined by any element of the <code>pWaitSemaphores</code> member of any element of <code>pBindInfo</code> executes on <code>queue</code>, no other queue <strong class=\"purple\">must</strong> be waiting on the same semaphore."
+          "text": " When a semaphore unsignal operation defined by any element of the <code>pWaitSemaphores</code> member of any element of <code>pBindInfo</code> executes on <code>queue</code>, there <strong class=\"purple\">must</strong> be no other queues waiting on the same semaphore."
         },
         {
           "vuid": "VUID-vkQueueBindSparse-pWaitSemaphores-01117",
@@ -22670,7 +22686,7 @@
         },
         {
           "vuid": "VUID-vkQueuePresentKHR-pWaitSemaphores-01294",
-          "text": " When a semaphore unsignal operation defined by the elements of the <code>pWaitSemaphores</code> member of <code>pPresentInfo</code> executes on <code>queue</code>, no other queue <strong class=\"purple\">must</strong> be waiting on the same semaphore."
+          "text": " When a semaphore unsignal operation defined by the elements of the <code>pWaitSemaphores</code> member of <code>pPresentInfo</code> executes on <code>queue</code>, there <strong class=\"purple\">must</strong> be no other queues waiting on the same semaphore."
         },
         {
           "vuid": "VUID-vkQueuePresentKHR-pWaitSemaphores-01295",
diff --git a/registry/vk.xml b/registry/vk.xml
index f76c0c8..bc1c63d 100644
--- a/registry/vk.xml
+++ b/registry/vk.xml
@@ -154,7 +154,7 @@
         <type category="define">// Vulkan 1.1 version number
 #define <name>VK_API_VERSION_1_1</name> <type>VK_MAKE_VERSION</type>(1, 1, 0)// Patch version should always be set to 0</type>
         <type category="define">// Version of this file
-#define <name>VK_HEADER_VERSION</name> 119</type>
+#define <name>VK_HEADER_VERSION</name> 120</type>
 
         <type category="define">
 #define <name>VK_DEFINE_HANDLE</name>(object) typedef struct object##_T* object;</type>
@@ -5040,12 +5040,11 @@
     <enums name="VkValidationCheckEXT" type="enum">
         <enum value="0"     name="VK_VALIDATION_CHECK_ALL_EXT"/>
         <enum value="1"     name="VK_VALIDATION_CHECK_SHADERS_EXT"/>
-            <comment>Placeholder for validation enums to be defined for VK_EXT_Validation_flags extension</comment>
     </enums>
     <enums name="VkValidationFeatureEnableEXT" type="enum">
         <enum value="0"     name="VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT"/>
         <enum value="1"     name="VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT"/>
-            <comment>Placeholder for validation feature enable enums to be defined for VK_EXT_validation_features extension</comment>
+        <enum value="2"     name="VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT"/>
     </enums>
     <enums name="VkValidationFeatureDisableEXT" type="enum">
         <enum value="0"     name="VK_VALIDATION_FEATURE_DISABLE_ALL_EXT"/>
@@ -5055,7 +5054,6 @@
         <enum value="4"     name="VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT"/>
         <enum value="5"     name="VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT"/>
         <enum value="6"     name="VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT"/>
-            <comment>Placeholder for validation feature disable enums to be defined for VK_EXT_validation_features extension</comment>
     </enums>
     <enums name="VkSubgroupFeatureFlagBits" type="bitmask">
         <enum bitpos="0"    name="VK_SUBGROUP_FEATURE_BASIC_BIT"              comment="Basic subgroup operations"/>
@@ -10412,6 +10410,7 @@
                 <enum offset="0" extends="VkObjectType"                  name="VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV"/>
                 <enum offset="0" extends="VkDebugReportObjectTypeEXT"    name="VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT"/>
                 <enum offset="0" extends="VkIndexType"                   name="VK_INDEX_TYPE_NONE_NV"/>
+                <type name="VkAccelerationStructureTypeNV"/>
                 <type name="VkRayTracingShaderGroupCreateInfoNV"/>
                 <type name="VkRayTracingShaderGroupTypeNV"/>
                 <type name="VkRayTracingPipelineCreateInfoNV"/>
@@ -11156,7 +11155,7 @@
         </extension>
         <extension name="VK_EXT_validation_features" number="248" type="instance" author="LUNARG" contact="Karl Schultz @karl-lunarg" supported="vulkan">
             <require>
-                <enum value="1"                                             name="VK_EXT_VALIDATION_FEATURES_SPEC_VERSION"/>
+                <enum value="2"                                             name="VK_EXT_VALIDATION_FEATURES_SPEC_VERSION"/>
                 <enum value="&quot;VK_EXT_validation_features&quot;"        name="VK_EXT_VALIDATION_FEATURES_EXTENSION_NAME"/>
                 <enum offset="0" extends="VkStructureType"                  name="VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT"/>
                 <type name="VkValidationFeaturesEXT"/>
diff --git a/registry/vkconventions.py b/registry/vkconventions.py
index 37235c1..7230fa2 100644
--- a/registry/vkconventions.py
+++ b/registry/vkconventions.py
@@ -22,6 +22,10 @@
 from conventions import ConventionsBase
 
 
+# Modified from default implementation - see category_requires_validation() below
+CATEGORIES_REQUIRING_VALIDATION = set(('handle', 'enum', 'bitmask'))
+
+
 class VulkanConventions(ConventionsBase):
     def formatExtension(self, name):
         """Mark up a name as an extension for the spec."""
@@ -38,14 +42,6 @@
         return False
 
     @property
-    def struct_macro(self):
-        return 'sname:'
-
-    @property
-    def external_macro(self):
-        return 'code:'
-
-    @property
     def structtype_member_name(self):
         """Return name of the structure type member"""
         return 'sType'
@@ -89,7 +85,7 @@
         """Return suffix of generated Asciidoctor files"""
         return '.txt'
 
-    def api_name(self, spectype = 'api'):
+    def api_name(self, spectype='api'):
         """Return API or specification name for citations in ref pages.ref
            pages should link to for
 
@@ -113,21 +109,6 @@
         return 'VK_'
 
     @property
-    def api_version_prefix(self):
-        """Return API core version token prefix"""
-        return 'VK_VERSION_'
-
-    @property
-    def KHR_prefix(self):
-        """Return extension name prefix for KHR extensions"""
-        return 'VK_KHR_'
-
-    @property
-    def EXT_prefix(self):
-        """Return extension name prefix for EXT extensions"""
-        return 'VK_EXT_'
-
-    @property
     def write_contacts(self):
         """Return whether contact list should be written to extension appendices"""
         return True
@@ -137,22 +118,10 @@
         """Return whether refpage include should be written to extension appendices"""
         return True
 
-    def writeFeature(self, featureExtraProtect, filename):
-        """Returns True if OutputGenerator.endFeature should write this feature.
-           Used in COutputGenerator
-        """
-        return True
-
-    def requires_error_validation(self, return_type):
-        """Returns True if the return_type element is an API result code
-           requiring error validation.
-        """
-        return False
-
     @property
-    def required_errors(self):
-        """Return a list of required error codes for validation."""
-        return []
+    def member_used_for_unique_vuid(self):
+        """Return the member name used in the VUID-...-...-unique ID."""
+        return self.structtype_member_name
 
     def is_externsync_command(self, protoname):
         """Returns True if the protoname element is an API command requiring
@@ -167,19 +136,7 @@
         """
         return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk'
 
-    def is_voidpointer_alias(self, tag, text, tail):
-        """Return True if the declaration components (tag,text,tail) of an
-           element represents a void * type
-        """
-        return tag == 'type' and text == 'void' and tail.startswith('*')
-
-    def make_voidpointer_alias(self, tail):
-        """Reformat a void * declaration to include the API alias macro.
-           Vulkan doesn't have an API alias macro, so do nothing.
-        """
-        return tail
-
-    def specURL(self, spectype = 'api'):
+    def specURL(self, spectype='api'):
         """Return public registry URL which ref pages should link to for the
            current all-extensions HTML specification, so xrefs in the
            asciidoc source that aren't to ref pages can link into it
@@ -232,3 +189,12 @@
         """
         return ('scripts', 'style')
 
+    @property
+    def zero(self):
+        return '`0`'
+
+    def category_requires_validation(self, category):
+        """Return True if the given type 'category' always requires validation.
+
+        Overridden because Vulkan doesn't require "valid" text for basetype in the spec right now."""
+        return category in CATEGORIES_REQUIRING_VALIDATION