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