summaryrefslogtreecommitdiff
path: root/codegen/vulkan/scripts/vkconventions.py
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/vulkan/scripts/vkconventions.py')
-rw-r--r--codegen/vulkan/scripts/vkconventions.py274
1 files changed, 274 insertions, 0 deletions
diff --git a/codegen/vulkan/scripts/vkconventions.py b/codegen/vulkan/scripts/vkconventions.py
new file mode 100644
index 00000000..a43f7121
--- /dev/null
+++ b/codegen/vulkan/scripts/vkconventions.py
@@ -0,0 +1,274 @@
+#!/usr/bin/python3 -i
+#
+# Copyright 2013-2021 The Khronos Group Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+# Working-group-specific style conventions,
+# used in generation.
+
+import re
+import os
+
+from conventions import ConventionsBase
+
+
+# Modified from default implementation - see category_requires_validation() below
+CATEGORIES_REQUIRING_VALIDATION = set(('handle', 'enum', 'bitmask'))
+
+# Tokenize into "words" for structure types, approximately per spec "Implicit Valid Usage" section 2.7.2
+# This first set is for things we recognize explicitly as words,
+# as exceptions to the general regex.
+# Ideally these would be listed in the spec as exceptions, as OpenXR does.
+SPECIAL_WORDS = set((
+ '16Bit', # VkPhysicalDevice16BitStorageFeatures
+ '8Bit', # VkPhysicalDevice8BitStorageFeaturesKHR
+ 'AABB', # VkGeometryAABBNV
+ 'ASTC', # VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT
+ 'D3D12', # VkD3D12FenceSubmitInfoKHR
+ 'Float16', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
+ 'ImagePipe', # VkImagePipeSurfaceCreateInfoFUCHSIA
+ 'Int64', # VkPhysicalDeviceShaderAtomicInt64FeaturesKHR
+ 'Int8', # VkPhysicalDeviceShaderFloat16Int8FeaturesKHR
+ 'MacOS', # VkMacOSSurfaceCreateInfoMVK
+ 'RGBA10X6', # VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT
+ 'Uint8', # VkPhysicalDeviceIndexTypeUint8FeaturesEXT
+ 'Win32', # VkWin32SurfaceCreateInfoKHR
+))
+# A regex to match any of the SPECIAL_WORDS
+EXCEPTION_PATTERN = r'(?P<exception>{})'.format(
+ '|'.join('(%s)' % re.escape(w) for w in SPECIAL_WORDS))
+MAIN_RE = re.compile(
+ # the negative lookahead is to prevent the all-caps pattern from being too greedy.
+ r'({}|([0-9]+)|([A-Z][a-z]+)|([A-Z][A-Z]*(?![a-z])))'.format(EXCEPTION_PATTERN))
+
+
+class VulkanConventions(ConventionsBase):
+ @property
+ def null(self):
+ """Preferred spelling of NULL."""
+ return '`NULL`'
+
+ @property
+ def struct_macro(self):
+ """Get the appropriate format macro for a structure.
+
+ Primarily affects generated valid usage statements.
+ """
+
+ return 'slink:'
+
+ @property
+ def constFlagBits(self):
+ """Returns True if static const flag bits should be generated, False if an enumerated type should be generated."""
+ return False
+
+ @property
+ def structtype_member_name(self):
+ """Return name of the structure type member"""
+ return 'sType'
+
+ @property
+ def nextpointer_member_name(self):
+ """Return name of the structure pointer chain member"""
+ return 'pNext'
+
+ @property
+ def valid_pointer_prefix(self):
+ """Return prefix to pointers which must themselves be valid"""
+ return 'valid'
+
+ def is_structure_type_member(self, paramtype, paramname):
+ """Determine if member type and name match the structure type member."""
+ return paramtype == 'VkStructureType' and paramname == self.structtype_member_name
+
+ def is_nextpointer_member(self, paramtype, paramname):
+ """Determine if member type and name match the next pointer chain member."""
+ return paramtype == 'void' and paramname == self.nextpointer_member_name
+
+ def generate_structure_type_from_name(self, structname):
+ """Generate a structure type name, like VK_STRUCTURE_TYPE_CREATE_INSTANCE_INFO"""
+
+ structure_type_parts = []
+ # Tokenize into "words"
+ for elem in MAIN_RE.findall(structname):
+ word = elem[0]
+ if word == 'Vk':
+ structure_type_parts.append('VK_STRUCTURE_TYPE')
+ else:
+ structure_type_parts.append(word.upper())
+ name = '_'.join(structure_type_parts)
+
+ # The simple-minded rules need modification for some structure names
+ subpats = [
+ [ r'_H_(26[45])_', r'_H\1_' ],
+ [ r'_VULKAN_([0-9])([0-9])_', r'_VULKAN_\1_\2_' ],
+ [ r'_DIRECT_FB_', r'_DIRECTFB_' ],
+ ]
+
+ for subpat in subpats:
+ name = re.sub(subpat[0], subpat[1], name)
+ return name
+
+ @property
+ def warning_comment(self):
+ """Return warning comment to be placed in header of generated Asciidoctor files"""
+ return '// WARNING: DO NOT MODIFY! This file is automatically generated from the vk.xml registry'
+
+ @property
+ def file_suffix(self):
+ """Return suffix of generated Asciidoctor files"""
+ return '.txt'
+
+ def api_name(self, spectype='api'):
+ """Return API or specification name for citations in ref pages.ref
+ pages should link to for
+
+ spectype is the spec this refpage is for: 'api' is the Vulkan API
+ Specification. Defaults to 'api'. If an unrecognized spectype is
+ given, returns None.
+ """
+ if spectype == 'api' or spectype is None:
+ return 'Vulkan'
+ else:
+ return None
+
+ @property
+ def api_prefix(self):
+ """Return API token prefix"""
+ return 'VK_'
+
+ @property
+ def write_contacts(self):
+ """Return whether contact list should be written to extension appendices"""
+ return True
+
+ @property
+ def write_refpage_include(self):
+ """Return whether refpage include should be written to extension appendices"""
+ return True
+
+ @property
+ def member_used_for_unique_vuid(self):
+ """Return the member name used in the VUID-...-...-unique ID."""
+ return self.structtype_member_name
+
+ def is_externsync_command(self, protoname):
+ """Returns True if the protoname element is an API command requiring
+ external synchronization
+ """
+ return protoname is not None and 'vkCmd' in protoname
+
+ def is_api_name(self, name):
+ """Returns True if name is in the reserved API namespace.
+ For Vulkan, these are names with a case-insensitive 'vk' prefix, or
+ a 'PFN_vk' function pointer type prefix.
+ """
+ return name[0:2].lower() == 'vk' or name[0:6] == 'PFN_vk'
+
+ def specURL(self, spectype='api'):
+ """Return public registry URL which ref pages should link to for the
+ current all-extensions HTML specification, so xrefs in the
+ asciidoc source that aren't to ref pages can link into it
+ instead. N.b. this may need to change on a per-refpage basis if
+ there are multiple documents involved.
+ """
+ return 'https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html'
+
+ @property
+ def xml_api_name(self):
+ """Return the name used in the default API XML registry for the default API"""
+ return 'vulkan'
+
+ @property
+ def registry_path(self):
+ """Return relpath to the default API XML registry in this project."""
+ return 'xml/vk.xml'
+
+ @property
+ def specification_path(self):
+ """Return relpath to the Asciidoctor specification sources in this project."""
+ return '{generated}/meta'
+
+ @property
+ def special_use_section_anchor(self):
+ """Return asciidoctor anchor name in the API Specification of the
+ section describing extension special uses in detail."""
+ return 'extendingvulkan-compatibility-specialuse'
+
+ @property
+ def extra_refpage_headers(self):
+ """Return any extra text to add to refpage headers."""
+ return 'include::{config}/attribs.txt[]'
+
+ @property
+ def extension_index_prefixes(self):
+ """Return a list of extension prefixes used to group extension refpages."""
+ return ['VK_KHR', 'VK_EXT', 'VK']
+
+ @property
+ def unified_flag_refpages(self):
+ """Return True if Flags/FlagBits refpages are unified, False if
+ they're separate.
+ """
+ return False
+
+ @property
+ def spec_reflow_path(self):
+ """Return the path to the spec source folder to reflow"""
+ return os.getcwd()
+
+ @property
+ def spec_no_reflow_dirs(self):
+ """Return a set of directories not to automatically descend into
+ when reflowing spec text
+ """
+ return ('scripts', 'style')
+
+ @property
+ def zero(self):
+ return '`0`'
+
+ def category_requires_validation(self, category):
+ """Return True if the given type 'category' always requires validation.
+
+ Overridden because Vulkan doesn't require "valid" text for basetype in the spec right now."""
+ return category in CATEGORIES_REQUIRING_VALIDATION
+
+ @property
+ def should_skip_checking_codes(self):
+ """Return True if more than the basic validation of return codes should
+ be skipped for a command.
+
+ Vulkan mostly relies on the validation layers rather than API
+ builtin error checking, so these checks are not appropriate.
+
+ For example, passing in a VkFormat parameter will not potentially
+ generate a VK_ERROR_FORMAT_NOT_SUPPORTED code."""
+
+ return True
+
+ def extension_include_string(self, ext):
+ """Return format string for include:: line for an extension appendix
+ file. ext is an object with the following members:
+ - name - extension string string
+ - vendor - vendor portion of name
+ - barename - remainder of name"""
+
+ return 'include::{{appendices}}/{name}{suffix}[]'.format(
+ name=ext.name, suffix=self.file_suffix)
+
+ @property
+ def refpage_generated_include_path(self):
+ """Return path relative to the generated reference pages, to the
+ generated API include files."""
+ return "{generated}"
+
+ def valid_flag_bit(self, bitpos):
+ """Return True if bitpos is an allowed numeric bit position for
+ an API flag bit.
+
+ Vulkan uses 32 bit Vk*Flags types, and assumes C compilers may
+ cause Vk*FlagBits values with bit 31 set to result in a 64 bit
+ enumerated type, so disallows such flags."""
+ return bitpos >= 0 and bitpos < 31