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