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