2020-12-28 19:15:37 +04:00
|
|
|
#!/usr/bin/python3 -i
|
|
|
|
#
|
2021-07-10 01:54:15 +04:00
|
|
|
# Copyright 2013-2021 The Khronos Group Inc.
|
2020-12-28 19:15:37 +04:00
|
|
|
#
|
|
|
|
# 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
|
2021-12-18 11:41:22 +04:00
|
|
|
'RGBA10X6', # VkPhysicalDeviceRGBA10X6FormatsFeaturesEXT
|
2020-12-28 19:15:37 +04:00
|
|
|
'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"""
|
2021-07-10 01:54:15 +04:00
|
|
|
|
2020-12-28 19:15:37 +04:00
|
|
|
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())
|
2021-07-10 01:54:15 +04:00
|
|
|
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
|
2020-12-28 19:15:37 +04:00
|
|
|
|
|
|
|
@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
|
2021-12-18 11:41:22 +04:00
|
|
|
asciidoc source that are not to ref pages can link into it
|
2020-12-28 19:15:37 +04:00
|
|
|
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
|
2021-12-18 11:41:22 +04:00
|
|
|
they are separate.
|
2020-12-28 19:15:37 +04:00
|
|
|
"""
|
|
|
|
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.
|
|
|
|
|
2021-12-18 11:41:22 +04:00
|
|
|
Overridden because Vulkan does not require "valid" text for basetype
|
|
|
|
in the spec right now."""
|
2020-12-28 19:15:37 +04:00
|
|
|
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
|