262 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/python3 -i
 | 
						|
#
 | 
						|
# Copyright (c) 2013-2020 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
 | 
						|
    '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())
 | 
						|
        return '_'.join(structure_type_parts)
 | 
						|
 | 
						|
    @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
 |