• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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