1#!/usr/bin/python3 2# Copyright 2016 The ANGLE Project Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5# 6# gen_vk_format_table.py: 7# Code generation for vk format map. See vk_format_map.json for data source. 8# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 9 10import json 11import math 12import pprint 13import os 14import re 15import sys 16 17sys.path.append('..') 18import angle_format 19 20template_table_autogen_cpp = """// GENERATED FILE - DO NOT EDIT. 21// Generated by {script_name} using data from {input_file_name} 22// 23// Copyright 2020 The ANGLE Project Authors. All rights reserved. 24// Use of this source code is governed by a BSD-style license that can be 25// found in the LICENSE file. 26// 27// {out_file_name}: 28// Queries for full Vulkan format information based on GL format. 29 30#include "libANGLE/renderer/vulkan/vk_format_utils.h" 31 32#include "image_util/loadimage.h" 33 34using namespace angle; 35 36namespace rx 37{{ 38namespace vk 39{{ 40 41void Format::initialize(RendererVk *renderer, 42 const angle::Format &angleFormat) 43{{ 44 switch (angleFormat.id) 45 {{ 46{format_case_data} 47 default: 48 UNREACHABLE(); 49 break; 50 }} 51}} 52 53VkFormat GetVkFormatFromFormatID(angle::FormatID formatID) 54{{ 55 static constexpr angle::FormatMap<VkFormat> kMap = {{ 56{format_id_cases} 57 }}; 58 59 return kMap[formatID]; 60}} 61 62angle::FormatID GetFormatIDFromVkFormat(VkFormat vkFormat) 63{{ 64 switch (vkFormat) 65 {{ 66{vk_format_cases} 67 default: 68 UNREACHABLE(); 69 return angle::FormatID::NONE; 70 }} 71}} 72}} // namespace vk 73}} // namespace rx 74""" 75 76empty_format_entry_template = """case angle::FormatID::{format_id}: 77// This format is not implemented in Vulkan. 78break; 79""" 80 81format_entry_template = """case angle::FormatID::{format_id}: 82mIntendedGLFormat = {internal_format}; 83{image_template} 84{buffer_template} 85break; 86""" 87 88image_basic_template = """mActualSampleOnlyImageFormatID = {image}; 89mImageInitializerFunction = {image_initializer};""" 90 91image_struct_template = "{{{image}, {image_initializer}}}" 92 93image_fallback_template = """{{ 94static constexpr ImageFormatInitInfo kInfo[] = {{{image_list}}}; 95initImageFallback(renderer, kInfo, ArraySize(kInfo)); 96}}""" 97 98buffer_basic_template = """mActualBufferFormatID = {buffer}; 99mVkBufferFormatIsPacked = {vk_buffer_format_is_packed}; 100mVertexLoadFunction = {vertex_load_function}; 101mVertexLoadRequiresConversion = {vertex_load_converts};""" 102 103buffer_struct_template = """{{{buffer}, {vk_buffer_format_is_packed}, 104{vertex_load_function}, {vertex_load_converts}}}""" 105 106buffer_fallback_template = """{{ 107static constexpr BufferFormatInitInfo kInfo[] = {{{buffer_list}}}; 108initBufferFallback(renderer, kInfo, ArraySize(kInfo), {buffer_compressed_offset}); 109}}""" 110 111 112def is_packed(format_id): 113 return "true" if "_PACK" in format_id else "false" 114 115 116def verify_vk_map_keys(angle_to_gl, vk_json_data): 117 """Verify that the keys in Vulkan format tables exist in the ANGLE table. If they don't, the 118 entry in the Vulkan file is incorrect and needs to be fixed.""" 119 120 no_error = True 121 for table in ["map", "fallbacks"]: 122 for angle_format in vk_json_data[table].keys(): 123 if not angle_format in angle_to_gl.keys(): 124 print("Invalid format " + angle_format + " in vk_format_map.json in " + table) 125 no_error = False 126 127 return no_error 128 129 130def get_vertex_copy_function(src_format, dst_format, vk_format): 131 if "_PACK" in vk_format: 132 pack_bits = int(re.search(r'_PACK(\d+)', vk_format).group(1)) 133 base_type = None 134 if pack_bits == 8: 135 base_type = 'byte' 136 elif pack_bits == 16: 137 base_type = 'short' 138 elif pack_bits == 32: 139 base_type = 'int' 140 else: 141 return 'nullptr' 142 return 'CopyNativeVertexData<GLu%s, 1, 1, 0>' % base_type 143 if 'R10G10B10A2' in src_format: 144 # When the R10G10B10A2 type can't be used by the vertex buffer, 145 # it needs to be converted to the type which can be used by it. 146 is_signed = 'false' if 'UINT' in src_format or 'UNORM' in src_format or 'USCALED' in src_format else 'true' 147 normalized = 'true' if 'NORM' in src_format else 'false' 148 to_float = 'false' if 'INT' in src_format else 'true' 149 to_half = to_float 150 return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, %s, %s>' % (is_signed, normalized, 151 to_float, to_half) 152 return angle_format.get_vertex_copy_function(src_format, dst_format) 153 154 155def gen_format_case(angle, internal_format, vk_json_data): 156 vk_map = vk_json_data["map"] 157 vk_fallbacks = vk_json_data["fallbacks"] 158 args = dict( 159 format_id=angle, internal_format=internal_format, image_template="", buffer_template="") 160 161 if ((angle not in vk_map) and (angle not in vk_fallbacks)): 162 return empty_format_entry_template.format(**args) 163 164 # get_formats returns override format (if any) + fallbacks 165 # this was necessary to support D32_UNORM. There is no appropriate override that allows 166 # us to fallback to D32_FLOAT, so now we leave the image override empty and function will 167 # give us the fallbacks. 168 def get_formats(format, type): 169 fallbacks = vk_fallbacks.get(format, {}).get(type, []) 170 if not isinstance(fallbacks, list): 171 fallbacks = [fallbacks] 172 173 compressed = vk_fallbacks.get(format, {}).get(type + "_compressed", []) 174 if not isinstance(compressed, list): 175 compressed = [compressed] 176 177 fallbacks += compressed 178 179 if format in vk_map: 180 fallbacks = [format] + fallbacks 181 182 return (fallbacks, len(fallbacks) - len(compressed)) 183 184 def image_args(format): 185 return dict( 186 image="angle::FormatID::" + format, 187 image_initializer=angle_format.get_internal_format_initializer( 188 internal_format, format)) 189 190 def buffer_args(format): 191 vk_buffer_format = vk_map[format] 192 return dict( 193 buffer="angle::FormatID::" + format, 194 vk_buffer_format_is_packed=is_packed(vk_buffer_format), 195 vertex_load_function=get_vertex_copy_function(angle, format, vk_buffer_format), 196 vertex_load_converts='false' if angle == format else 'true', 197 ) 198 199 images, images_compressed_offset = get_formats(angle, "image") 200 if len(images) == 1: 201 args.update(image_template=image_basic_template) 202 args.update(image_args(images[0])) 203 elif len(images) > 1: 204 args.update( 205 image_template=image_fallback_template, 206 image_list=", ".join(image_struct_template.format(**image_args(i)) for i in images)) 207 208 buffers, buffers_compressed_offset = get_formats(angle, "buffer") 209 if len(buffers) == 1: 210 args.update(buffer_template=buffer_basic_template) 211 args.update(buffer_args(buffers[0])) 212 elif len(buffers) > 1: 213 args.update( 214 buffer_template=buffer_fallback_template, 215 buffer_list=", ".join( 216 buffer_struct_template.format(**buffer_args(i)) for i in buffers), 217 buffer_compressed_offset=buffers_compressed_offset) 218 219 return format_entry_template.format(**args).format(**args) 220 221 222def get_format_id_case(format_id, vk_format): 223 return "{angle::FormatID::%s, %s}" % (format_id, vk_format) 224 225 226def get_vk_format_case(format_id, vk_format): 227 return """\ 228 case %s: 229 return angle::FormatID::%s; 230""" % (vk_format, format_id) 231 232 233def main(): 234 235 input_file_name = 'vk_format_map.json' 236 out_file_name = 'vk_format_table_autogen.cpp' 237 238 # auto_script parameters. 239 if len(sys.argv) > 1: 240 inputs = ['../angle_format.py', '../angle_format_map.json', input_file_name] 241 outputs = [out_file_name] 242 243 if sys.argv[1] == 'inputs': 244 print(','.join(inputs)) 245 elif sys.argv[1] == 'outputs': 246 print(','.join(outputs)) 247 else: 248 print('Invalid script parameters') 249 return 1 250 return 0 251 252 angle_to_gl = angle_format.load_inverse_table(os.path.join('..', 'angle_format_map.json')) 253 vk_json_data = angle_format.load_json(input_file_name) 254 255 if not verify_vk_map_keys(angle_to_gl, vk_json_data): 256 return 1 257 258 format_id_cases = [ 259 get_format_id_case(format_id, vk_format) 260 for format_id, vk_format in sorted(vk_json_data["map"].items()) 261 ] 262 263 vk_format_cases = [ 264 get_vk_format_case(format_id, vk_format) 265 for format_id, vk_format in sorted(vk_json_data["map"].items()) 266 ] 267 268 vk_cases = [ 269 gen_format_case(angle, gl, vk_json_data) for angle, gl in sorted(angle_to_gl.items()) 270 ] 271 272 output_cpp = template_table_autogen_cpp.format( 273 format_case_data="\n".join(vk_cases), 274 format_id_cases=",\n".join(format_id_cases), 275 vk_format_cases="".join(vk_format_cases), 276 script_name=os.path.basename(__file__), 277 out_file_name=out_file_name, 278 input_file_name=input_file_name) 279 280 with open(out_file_name, 'wt') as out_file: 281 out_file.write(output_cpp) 282 out_file.close() 283 return 0 284 285 286if __name__ == '__main__': 287 sys.exit(main()) 288