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