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