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