1e5c31af7Sopenharmony_ci#!/usr/bin/python3 -i 2e5c31af7Sopenharmony_ci# 3e5c31af7Sopenharmony_ci# Copyright 2013-2024 The Khronos Group Inc. 4e5c31af7Sopenharmony_ci# 5e5c31af7Sopenharmony_ci# SPDX-License-Identifier: Apache-2.0 6e5c31af7Sopenharmony_ci 7e5c31af7Sopenharmony_cifrom generator import OutputGenerator, write 8e5c31af7Sopenharmony_cifrom spec_tools.attributes import ExternSyncEntry 9e5c31af7Sopenharmony_cifrom spec_tools.util import getElemName 10e5c31af7Sopenharmony_ci 11e5c31af7Sopenharmony_ciimport pdb 12e5c31af7Sopenharmony_ci 13e5c31af7Sopenharmony_ciclass FormatsOutputGenerator(OutputGenerator): 14e5c31af7Sopenharmony_ci """FormatsOutputGenerator - subclass of OutputGenerator. 15e5c31af7Sopenharmony_ci Generates AsciiDoc includes of the table for the format chapters 16e5c31af7Sopenharmony_ci of the API specification. 17e5c31af7Sopenharmony_ci 18e5c31af7Sopenharmony_ci ---- methods ---- 19e5c31af7Sopenharmony_ci FormatsOutputGenerator(errFile, warnFile, diagFile) - args as for 20e5c31af7Sopenharmony_ci OutputGenerator. Defines additional internal state. 21e5c31af7Sopenharmony_ci ---- methods overriding base class ---- 22e5c31af7Sopenharmony_ci genCmd(cmdinfo)""" 23e5c31af7Sopenharmony_ci 24e5c31af7Sopenharmony_ci def __init__(self, *args, **kwargs): 25e5c31af7Sopenharmony_ci super().__init__(*args, **kwargs) 26e5c31af7Sopenharmony_ci 27e5c31af7Sopenharmony_ci def beginFile(self, genOpts): 28e5c31af7Sopenharmony_ci OutputGenerator.beginFile(self, genOpts) 29e5c31af7Sopenharmony_ci 30e5c31af7Sopenharmony_ci # List of all the formats elements 31e5c31af7Sopenharmony_ci self.formats = [] 32e5c31af7Sopenharmony_ci # <format, condition as asciidoc string> 33e5c31af7Sopenharmony_ci self.format_conditions = dict() 34e5c31af7Sopenharmony_ci # <class, {'formats' : [], 'meta' : {} }> 35e5c31af7Sopenharmony_ci self.format_classes = dict() 36e5c31af7Sopenharmony_ci # {'packedSize' : ['format', 'format', ...]} 37e5c31af7Sopenharmony_ci self.packed_info = dict() 38e5c31af7Sopenharmony_ci # {VkFormat : SpirvFormat} 39e5c31af7Sopenharmony_ci self.spirv_image_format = dict() 40e5c31af7Sopenharmony_ci # <format, [{plane_info}, ...]> 41e5c31af7Sopenharmony_ci self.plane_format = dict() 42e5c31af7Sopenharmony_ci 43e5c31af7Sopenharmony_ci def endFile(self): 44e5c31af7Sopenharmony_ci 45e5c31af7Sopenharmony_ci # Generate compatibility table 46e5c31af7Sopenharmony_ci compatibility_table = [] 47e5c31af7Sopenharmony_ci for class_name, info in self.format_classes.items(): 48e5c31af7Sopenharmony_ci # Do an initial loop of formats in class to see if whole class is a single condition 49e5c31af7Sopenharmony_ci class_condition = None 50e5c31af7Sopenharmony_ci for index, format in enumerate(info['formats']): 51e5c31af7Sopenharmony_ci condition = self.format_conditions[format] 52e5c31af7Sopenharmony_ci if (condition == None) or (class_condition != None and class_condition != condition): 53e5c31af7Sopenharmony_ci class_condition = None 54e5c31af7Sopenharmony_ci break 55e5c31af7Sopenharmony_ci else: 56e5c31af7Sopenharmony_ci class_condition = condition 57e5c31af7Sopenharmony_ci 58e5c31af7Sopenharmony_ci # If not single class condition for the class, next check if a single format has a condition 59e5c31af7Sopenharmony_ci # Move all condition formats to the front of array to make listing the formats in table 60e5c31af7Sopenharmony_ci if class_condition == None: 61e5c31af7Sopenharmony_ci condition_list = [] 62e5c31af7Sopenharmony_ci noncondition_list = [] 63e5c31af7Sopenharmony_ci for index, format in enumerate(info['formats']): 64e5c31af7Sopenharmony_ci if self.format_conditions[format] == None: 65e5c31af7Sopenharmony_ci noncondition_list.append(format) 66e5c31af7Sopenharmony_ci else: 67e5c31af7Sopenharmony_ci condition_list.append(format) 68e5c31af7Sopenharmony_ci info['formats'] = condition_list + noncondition_list 69e5c31af7Sopenharmony_ci 70e5c31af7Sopenharmony_ci if class_condition != None: 71e5c31af7Sopenharmony_ci compatibility_table.append('ifdef::{}[]'.format(class_condition)) 72e5c31af7Sopenharmony_ci 73e5c31af7Sopenharmony_ci compatibility_table.append("| {} +".format(class_name)) 74e5c31af7Sopenharmony_ci compatibility_table.append(" Block size {} byte +".format(info['meta']['blockSize'])) 75e5c31af7Sopenharmony_ci compatibility_table.append(" {} block extent +".format(info['meta']['blockExtent'].replace(",", "x"))) 76e5c31af7Sopenharmony_ci compatibility_table.append(" {} texel/block |".format(info['meta']['texelsPerBlock'])) 77e5c31af7Sopenharmony_ci 78e5c31af7Sopenharmony_ci for index, format in enumerate(info['formats']): 79e5c31af7Sopenharmony_ci format_condition = self.format_conditions[format] 80e5c31af7Sopenharmony_ci if format_condition != None and class_condition == None: 81e5c31af7Sopenharmony_ci compatibility_table.append('ifdef::{}[]'.format(format_condition)) 82e5c31af7Sopenharmony_ci suffix = ", +" if index != len(info['formats']) - 1 else "" 83e5c31af7Sopenharmony_ci compatibility_table.append(" ename:{}{}".format(format, suffix)) 84e5c31af7Sopenharmony_ci if format_condition != None and class_condition == None: 85e5c31af7Sopenharmony_ci compatibility_table.append('endif::{}[]'.format(format_condition)) 86e5c31af7Sopenharmony_ci 87e5c31af7Sopenharmony_ci if class_condition != None: 88e5c31af7Sopenharmony_ci compatibility_table.append('endif::{}[]'.format(class_condition)) 89e5c31af7Sopenharmony_ci self.writeBlock(f'compatibility{self.file_suffix}', compatibility_table) 90e5c31af7Sopenharmony_ci 91e5c31af7Sopenharmony_ci # Generate packed format list 92e5c31af7Sopenharmony_ci packed_table = [] 93e5c31af7Sopenharmony_ci for packed_size, formats in self.packed_info.items(): 94e5c31af7Sopenharmony_ci packed_table.append(' * <<formats-packed-{}-bit,Packed into {}-bit data types>>:'.format(packed_size, packed_size)) 95e5c31af7Sopenharmony_ci # Do an initial loop of formats with same packed size to group conditional together for easier reading of final asciidoc 96e5c31af7Sopenharmony_ci sorted_formats = dict() # {condition : formats} 97e5c31af7Sopenharmony_ci for format in formats: 98e5c31af7Sopenharmony_ci format_condition = self.format_conditions[format] 99e5c31af7Sopenharmony_ci if format_condition == None: 100e5c31af7Sopenharmony_ci format_condition = "None" # to allow as a key in the dict 101e5c31af7Sopenharmony_ci if format_condition not in sorted_formats: 102e5c31af7Sopenharmony_ci sorted_formats[format_condition] = [] 103e5c31af7Sopenharmony_ci sorted_formats[format_condition].append(format) 104e5c31af7Sopenharmony_ci 105e5c31af7Sopenharmony_ci for condition, condition_formats in sorted_formats.items(): 106e5c31af7Sopenharmony_ci if condition != "None": 107e5c31af7Sopenharmony_ci packed_table.append('ifdef::{}[]'.format(condition)) 108e5c31af7Sopenharmony_ci for format in condition_formats: 109e5c31af7Sopenharmony_ci packed_table.append(' ** ename:{}'.format(format)) 110e5c31af7Sopenharmony_ci if condition != "None": 111e5c31af7Sopenharmony_ci packed_table.append('endif::{}[]'.format(condition)) 112e5c31af7Sopenharmony_ci self.writeBlock(f'packed{self.file_suffix}', packed_table) 113e5c31af7Sopenharmony_ci 114e5c31af7Sopenharmony_ci # Generate SPIR-V Image Format Compatibility 115e5c31af7Sopenharmony_ci spirv_image_format_table = [] 116e5c31af7Sopenharmony_ci spirv_image_format_table.append('|code:Unknown|Any') 117e5c31af7Sopenharmony_ci for vk_format, spirv_format in self.spirv_image_format.items(): 118e5c31af7Sopenharmony_ci spirv_image_format_table.append('|code:{}|ename:{}'.format(spirv_format, vk_format)) 119e5c31af7Sopenharmony_ci self.writeBlock(f'spirvimageformat{self.file_suffix}', spirv_image_format_table) 120e5c31af7Sopenharmony_ci 121e5c31af7Sopenharmony_ci # Generate Plane Format Compatibility Table 122e5c31af7Sopenharmony_ci plane_format_table = [] 123e5c31af7Sopenharmony_ci for format_name, plane_infos in self.plane_format.items(): 124e5c31af7Sopenharmony_ci format_condition = self.format_conditions[format_name] 125e5c31af7Sopenharmony_ci # The table is already in a ifdef::VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion[] 126e5c31af7Sopenharmony_ci # so no need to duplicate the condition 127e5c31af7Sopenharmony_ci add_condition = False if format_condition == 'None' or format_condition == 'VK_VERSION_1_1,VK_KHR_sampler_ycbcr_conversion' else True 128e5c31af7Sopenharmony_ci 129e5c31af7Sopenharmony_ci if add_condition: 130e5c31af7Sopenharmony_ci plane_format_table.append('ifdef::{}[]'.format(format_condition)) 131e5c31af7Sopenharmony_ci 132e5c31af7Sopenharmony_ci plane_format_table.append('4+| *ename:{}*'.format(format_name)) 133e5c31af7Sopenharmony_ci for plane_info in plane_infos: 134e5c31af7Sopenharmony_ci width_divisor = 'w' 135e5c31af7Sopenharmony_ci height_divisor = 'h' 136e5c31af7Sopenharmony_ci if plane_info['widthDivisor'] != 1: 137e5c31af7Sopenharmony_ci width_divisor += '/{}'.format(plane_info['widthDivisor']) 138e5c31af7Sopenharmony_ci if plane_info['heightDivisor'] != 1: 139e5c31af7Sopenharmony_ci height_divisor += '/{}'.format(plane_info['heightDivisor']) 140e5c31af7Sopenharmony_ci 141e5c31af7Sopenharmony_ci plane_format_table.append('^| {} ^| ename:{} ^| {} ^| {}'.format(plane_info['index'], 142e5c31af7Sopenharmony_ci plane_info['compatible'], 143e5c31af7Sopenharmony_ci width_divisor, 144e5c31af7Sopenharmony_ci height_divisor)) 145e5c31af7Sopenharmony_ci if add_condition: 146e5c31af7Sopenharmony_ci plane_format_table.append('endif::{}[]'.format(format_condition)) 147e5c31af7Sopenharmony_ci self.writeBlock(f'planeformat{self.file_suffix}', plane_format_table) 148e5c31af7Sopenharmony_ci 149e5c31af7Sopenharmony_ci # Finish processing in superclass 150e5c31af7Sopenharmony_ci OutputGenerator.endFile(self) 151e5c31af7Sopenharmony_ci 152e5c31af7Sopenharmony_ci def writeBlock(self, basename, contents): 153e5c31af7Sopenharmony_ci """Generate an include file. 154e5c31af7Sopenharmony_ci 155e5c31af7Sopenharmony_ci - directory - subdirectory to put file in 156e5c31af7Sopenharmony_ci - basename - base name of the file 157e5c31af7Sopenharmony_ci - contents - contents of the file (Asciidoc boilerplate aside)""" 158e5c31af7Sopenharmony_ci 159e5c31af7Sopenharmony_ci filename = self.genOpts.directory + '/' + basename 160e5c31af7Sopenharmony_ci self.logMsg('diag', '# Generating include file:', filename) 161e5c31af7Sopenharmony_ci with open(filename, 'w', encoding='utf-8') as fp: 162e5c31af7Sopenharmony_ci write(self.genOpts.conventions.warning_comment, file=fp) 163e5c31af7Sopenharmony_ci 164e5c31af7Sopenharmony_ci if len(contents) > 0: 165e5c31af7Sopenharmony_ci for str in contents: 166e5c31af7Sopenharmony_ci write(str, file=fp) 167e5c31af7Sopenharmony_ci else: 168e5c31af7Sopenharmony_ci self.logMsg('diag', '# No contents for:', filename) 169e5c31af7Sopenharmony_ci 170e5c31af7Sopenharmony_ci def genFormat(self, format, formatinfo, alias): 171e5c31af7Sopenharmony_ci """Generate Formats 172e5c31af7Sopenharmony_ci 173e5c31af7Sopenharmony_ci formatinfo - dictionary entry for an XML <format> element 174e5c31af7Sopenharmony_ci name - name attribute of format.elem""" 175e5c31af7Sopenharmony_ci 176e5c31af7Sopenharmony_ci OutputGenerator.genFormat(self, format, formatinfo, alias) 177e5c31af7Sopenharmony_ci elem = format.elem 178e5c31af7Sopenharmony_ci format_name = elem.get('name') 179e5c31af7Sopenharmony_ci 180e5c31af7Sopenharmony_ci self.formats.append(elem) 181e5c31af7Sopenharmony_ci self.format_conditions[format_name] = format.condition 182e5c31af7Sopenharmony_ci 183e5c31af7Sopenharmony_ci # Create format class data structure to be processed later 184e5c31af7Sopenharmony_ci class_name = elem.get('class') 185e5c31af7Sopenharmony_ci class_meta = { 186e5c31af7Sopenharmony_ci 'blockSize' : elem.get('blockSize'), 187e5c31af7Sopenharmony_ci 'texelsPerBlock' : elem.get('texelsPerBlock'), 188e5c31af7Sopenharmony_ci # default extent 189e5c31af7Sopenharmony_ci 'blockExtent' : "1,1,1" if elem.get('blockExtent') == None else elem.get('blockExtent') 190e5c31af7Sopenharmony_ci } 191e5c31af7Sopenharmony_ci 192e5c31af7Sopenharmony_ci if class_name in self.format_classes: 193e5c31af7Sopenharmony_ci self.format_classes[class_name]['formats'].append(format_name) 194e5c31af7Sopenharmony_ci # Assert all classes are using same meta info 195e5c31af7Sopenharmony_ci if class_meta != self.format_classes[class_name]['meta']: 196e5c31af7Sopenharmony_ci self.logMsg('error', 'Class meta info is not consistent for class ', class_name) 197e5c31af7Sopenharmony_ci else: 198e5c31af7Sopenharmony_ci self.format_classes[class_name] = { 199e5c31af7Sopenharmony_ci 'formats' : [format_name], 200e5c31af7Sopenharmony_ci 'meta' : class_meta 201e5c31af7Sopenharmony_ci } 202e5c31af7Sopenharmony_ci 203e5c31af7Sopenharmony_ci # Build list of formats with packed info in xml 204e5c31af7Sopenharmony_ci packed = elem.get('packed') 205e5c31af7Sopenharmony_ci if packed is not None: 206e5c31af7Sopenharmony_ci if packed not in self.packed_info: 207e5c31af7Sopenharmony_ci self.packed_info[packed] = [] 208e5c31af7Sopenharmony_ci self.packed_info[packed].append(format_name) 209e5c31af7Sopenharmony_ci 210e5c31af7Sopenharmony_ci # Currently there is only at most one <spirvimageformat> 211e5c31af7Sopenharmony_ci spirv_image_format = elem.find('spirvimageformat') 212e5c31af7Sopenharmony_ci if (spirv_image_format is not None): 213e5c31af7Sopenharmony_ci self.spirv_image_format[format_name] = spirv_image_format.get('name') 214e5c31af7Sopenharmony_ci 215e5c31af7Sopenharmony_ci for plane in elem.iterfind('plane'): 216e5c31af7Sopenharmony_ci if format_name not in self.plane_format: 217e5c31af7Sopenharmony_ci # create list if first time 218e5c31af7Sopenharmony_ci self.plane_format[format_name] = [] 219e5c31af7Sopenharmony_ci self.plane_format[format_name].append({ 220e5c31af7Sopenharmony_ci 'index' : int(plane.get('index')), 221e5c31af7Sopenharmony_ci 'widthDivisor' : int(plane.get('widthDivisor')), 222e5c31af7Sopenharmony_ci 'heightDivisor' : int(plane.get('heightDivisor')), 223e5c31af7Sopenharmony_ci 'compatible' : plane.get('compatible'), 224e5c31af7Sopenharmony_ci }) 225