1#!/usr/bin/python3 -i 2# 3# Copyright 2013-2023 The Khronos Group Inc. 4# 5# SPDX-License-Identifier: Apache-2.0 6 7# Working-group-specific style conventions, 8# used in generation. 9 10import re 11import os 12 13from spec_tools.conventions import ConventionsBase 14 15# Modified from default implementation - see category_requires_validation() below 16CATEGORIES_REQUIRING_VALIDATION = set(('handle', 'enum', 'bitmask')) 17 18# Tokenize into "words" for structure types, approximately per spec "Implicit Valid Usage" section 2.7.2 19# This first set is for things we recognize explicitly as words, 20# as exceptions to the general regex. 21# Ideally these would be listed in the spec as exceptions, as OpenXR does. 22SPECIAL_WORDS = set(( 23 '16Bit', # VkPhysicalDevice16BitStorageFeatures 24 '2D', # VkPhysicalDeviceImage2DViewOf3DFeaturesEXT 25 '3D', # VkPhysicalDeviceImage2DViewOf3DFeaturesEXT 26 '8Bit', # VkPhysicalDevice8BitStorageFeaturesKHR 27 'AABB', # VkGeometryAABBNV 28 'ASTC', # VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT 29 'D3D12', # VkD3D12FenceSubmitInfoKHR 30 'Float16', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR 31 'ImagePipe', # VkImagePipeSurfaceCreateInfoFUCHSIA 32 'Int64', # VkPhysicalDeviceShaderAtomicInt64FeaturesKHR 33 'Int8', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR 34 'MacOS', # VkMacOSSurfaceCreateInfoMVK 35 'RGBA10X6', # VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT 36 'Uint8', # VkPhysicalDeviceIndexTypeUint8FeaturesEXT 37 'Win32', # VkWin32SurfaceCreateInfoKHR 38)) 39# A regex to match any of the SPECIAL_WORDS 40EXCEPTION_PATTERN = r'(?P<exception>{})'.format( 41 '|'.join('(%s)' % re.escape(w) for w in SPECIAL_WORDS)) 42MAIN_RE = re.compile( 43 # the negative lookahead is to prevent the all-caps pattern from being too greedy. 44 r'({}|([0-9]+)|([A-Z][a-z]+)|([A-Z][A-Z]*(?![a-z])))'.format(EXCEPTION_PATTERN)) 45 46 47class VulkanConventions(ConventionsBase): 48 @property 49 def null(self): 50 """Preferred spelling of NULL.""" 51 return '`NULL`' 52 53 def formatExtension(self, name): 54 """Mark up an extension name as a link the spec.""" 55 return '`apiext:{}`'.format(name) 56 57 @property 58 def struct_macro(self): 59 """Get the appropriate format macro for a structure. 60 61 Primarily affects generated valid usage statements. 62 """ 63 64 return 'slink:' 65 66 @property 67 def constFlagBits(self): 68 """Returns True if static const flag bits should be generated, False if an enumerated type should be generated.""" 69 return False 70 71 @property 72 def structtype_member_name(self): 73 """Return name of the structure type member""" 74 return 'sType' 75 76 @property 77 def nextpointer_member_name(self): 78 """Return name of the structure pointer chain member""" 79 return 'pNext' 80 81 @property 82 def valid_pointer_prefix(self): 83 """Return prefix to pointers which must themselves be valid""" 84 return 'valid' 85 86 def is_structure_type_member(self, paramtype, paramname): 87 """Determine if member type and name match the structure type member.""" 88 return paramtype == 'VkStructureType' and paramname == self.structtype_member_name 89 90 def is_nextpointer_member(self, paramtype, paramname): 91 """Determine if member type and name match the next pointer chain member.""" 92 return paramtype == 'void' and paramname == self.nextpointer_member_name 93 94 def generate_structure_type_from_name(self, structname): 95 """Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO""" 96 97 structure_type_parts = [] 98 # Tokenize into "words" 99 for elem in MAIN_RE.findall(structname): 100 word = elem[0] 101 if word == 'Vk': 102 structure_type_parts.append('VK_STRUCTURE_TYPE') 103 else: 104 structure_type_parts.append(word.upper()) 105 name = '_'.join(structure_type_parts) 106 107 # The simple-minded rules need modification for some structure names 108 subpats = [ 109 [ r'_H_(26[45])_', r'_H\1_' ], 110 [ r'_VULKAN_([0-9])([0-9])_', r'_VULKAN_\1_\2_' ], 111 [ r'_VULKAN_SC_([0-9])([0-9])_',r'_VULKAN_SC_\1_\2_' ], 112 [ r'_DIRECT_FB_', r'_DIRECTFB_' ], 113 [ r'_VULKAN_SC_10', r'_VULKAN_SC_1_0' ], 114 115 ] 116 117 for subpat in subpats: 118 name = re.sub(subpat[0], subpat[1], name) 119 return name 120 121 @property 122 def warning_comment(self): 123 """Return warning comment to be placed in header of generated Asciidoctor files""" 124 return '// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry' 125 126 @property 127 def file_suffix(self): 128 """Return suffix of generated Asciidoctor files""" 129 return '.adoc' 130 131 def api_name(self, spectype='api'): 132 """Return API or specification name for citations in ref pages.ref 133 pages should link to for 134 135 spectype is the spec this refpage is for: 'api' is the Vulkan API 136 Specification. Defaults to 'api'. If an unrecognized spectype is 137 given, returns None. 138 """ 139 if spectype == 'api' or spectype is None: 140 return 'Vulkan' 141 else: 142 return None 143 144 @property 145 def api_prefix(self): 146 """Return API token prefix""" 147 return 'VK_' 148 149 @property 150 def write_contacts(self): 151 """Return whether contact list should be written to extension appendices""" 152 return True 153 154 @property 155 def write_refpage_include(self): 156 """Return whether refpage include should be written to extension appendices""" 157 return True 158 159 @property 160 def member_used_for_unique_vuid(self): 161 """Return the member name used in the VUID-...-...-unique ID.""" 162 return self.structtype_member_name 163 164 def is_externsync_command(self, protoname): 165 """Returns True if the protoname element is an API command requiring 166 external synchronization 167 """ 168 return protoname is not None and 'vkCmd' in protoname 169 170 def is_api_name(self, name): 171 """Returns True if name is in the reserved API namespace. 172 For Vulkan, these are names with a case-insensitive 'vk' prefix, or 173 a 'PFN_vk' function pointer type prefix. 174 """ 175 return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk' 176 177 def specURL(self, spectype='api'): 178 """Return public registry URL which ref pages should link to for the 179 current all-extensions HTML specification, so xrefs in the 180 asciidoc source that are not to ref pages can link into it 181 instead. N.b. this may need to change on a per-refpage basis if 182 there are multiple documents involved. 183 """ 184 return 'https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html' 185 186 @property 187 def xml_api_name(self): 188 """Return the name used in the default API XML registry for the default API""" 189 return 'vulkan' 190 191 @property 192 def registry_path(self): 193 """Return relpath to the default API XML registry in this project.""" 194 return 'xml/vk.xml' 195 196 @property 197 def specification_path(self): 198 """Return relpath to the Asciidoctor specification sources in this project.""" 199 return '{generated}/meta' 200 201 @property 202 def special_use_section_anchor(self): 203 """Return asciidoctor anchor name in the API Specification of the 204 section describing extension special uses in detail.""" 205 return 'extendingvulkan-compatibility-specialuse' 206 207 @property 208 def extension_index_prefixes(self): 209 """Return a list of extension prefixes used to group extension refpages.""" 210 return ['VK_KHR', 'VK_EXT', 'VK'] 211 212 @property 213 def unified_flag_refpages(self): 214 """Return True if Flags/FlagBits refpages are unified, False if 215 they are separate. 216 """ 217 return False 218 219 @property 220 def spec_reflow_path(self): 221 """Return the path to the spec source folder to reflow""" 222 return os.getcwd() 223 224 @property 225 def spec_no_reflow_dirs(self): 226 """Return a set of directories not to automatically descend into 227 when reflowing spec text 228 """ 229 return ('scripts', 'style') 230 231 @property 232 def zero(self): 233 return '`0`' 234 235 def category_requires_validation(self, category): 236 """Return True if the given type 'category' always requires validation. 237 238 Overridden because Vulkan does not require "valid" text for basetype 239 in the spec right now.""" 240 return category in CATEGORIES_REQUIRING_VALIDATION 241 242 @property 243 def should_skip_checking_codes(self): 244 """Return True if more than the basic validation of return codes should 245 be skipped for a command. 246 247 Vulkan mostly relies on the validation layers rather than API 248 builtin error checking, so these checks are not appropriate. 249 250 For example, passing in a VkFormat parameter will not potentially 251 generate a VK_ERROR_FORMAT_NOT_SUPPORTED code.""" 252 253 return True 254 255 def extension_file_path(self, name): 256 """Return file path to an extension appendix relative to a directory 257 containing all such appendices. 258 - name - extension name""" 259 260 return f'{name}{self.file_suffix}' 261 262 def valid_flag_bit(self, bitpos): 263 """Return True if bitpos is an allowed numeric bit position for 264 an API flag bit. 265 266 Vulkan uses 32 bit Vk*Flags types, and assumes C compilers may 267 cause Vk*FlagBits values with bit 31 set to result in a 64 bit 268 enumerated type, so disallows such flags.""" 269 return bitpos >= 0 and bitpos < 31 270 271 @property 272 def extra_refpage_headers(self): 273 """Return any extra text to add to refpage headers.""" 274 return 'include::{config}/attribs.adoc[]' 275 276 @property 277 def extra_refpage_body(self): 278 """Return any extra text (following the title) for generated 279 reference pages.""" 280 return 'include::{generated}/specattribs.adoc[]' 281 282 283class VulkanSCConventions(VulkanConventions): 284 285 def specURL(self, spectype='api'): 286 """Return public registry URL which ref pages should link to for the 287 current all-extensions HTML specification, so xrefs in the 288 asciidoc source that are not to ref pages can link into it 289 instead. N.b. this may need to change on a per-refpage basis if 290 there are multiple documents involved. 291 """ 292 return 'https://registry.khronos.org/vulkansc/specs/1.0-extensions/html/vkspec.html' 293 294 @property 295 def xml_api_name(self): 296 """Return the name used in the default API XML registry for the default API""" 297 return 'vulkansc' 298 299