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(Renderer *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(const Renderer *renderer, angle::FormatID formatID) 54{{ 55 static constexpr angle::FormatMap<VkFormat> kMap = {{ 56{format_id_cases} 57 }}; 58 59 return AdjustASTCFormatForHDR(renderer, 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_external_template = """mActualSampleOnlyImageFormatID = {image}; 92mActualRenderableImageFormatID = {image}; 93mImageInitializerFunction = {image_initializer};""" 94 95image_struct_template = "{{{image}, {image_initializer}}}" 96 97image_fallback_template = """{{ 98static constexpr ImageFormatInitInfo kInfo[] = {{{image_list}}}; 99initImageFallback(renderer, kInfo, ArraySize(kInfo)); 100}}""" 101 102buffer_basic_template = """mActualBufferFormatID = {buffer}; 103mVkBufferFormatIsPacked = {vk_buffer_format_is_packed}; 104mVertexLoadFunction = {vertex_load_function}; 105mVertexLoadRequiresConversion = {vertex_load_converts};""" 106 107buffer_struct_template = """{{{buffer}, {vk_buffer_format_is_packed}, 108{vertex_load_function}, {vertex_load_converts}}}""" 109 110buffer_fallback_template = """{{ 111static constexpr BufferFormatInitInfo kInfo[] = {{{buffer_list}}}; 112initBufferFallback(renderer, kInfo, ArraySize(kInfo), {buffer_compressed_offset}); 113}}""" 114 115 116def is_packed(format_id): 117 return "true" if "_PACK" in format_id else "false" 118 119 120def verify_vk_map_keys(angle_to_gl, vk_json_data): 121 """Verify that the keys in Vulkan format tables exist in the ANGLE table. If they don't, the 122 entry in the Vulkan file is incorrect and needs to be fixed.""" 123 124 no_error = True 125 for table in ["map", "fallbacks"]: 126 for angle_format in vk_json_data[table].keys(): 127 if not angle_format in angle_to_gl.keys(): 128 print("Invalid format " + angle_format + " in vk_format_map.json in " + table) 129 no_error = False 130 131 return no_error 132 133 134def get_vertex_copy_function(src_format, dst_format, vk_format): 135 if "_PACK" in vk_format: 136 pack_bits = int(re.search(r'_PACK(\d+)', vk_format).group(1)) 137 base_type = None 138 if pack_bits == 8: 139 base_type = 'byte' 140 elif pack_bits == 16: 141 base_type = 'short' 142 elif pack_bits == 32: 143 base_type = 'int' 144 else: 145 return 'nullptr' 146 return 'CopyNativeVertexData<GLu%s, 1, 1, 0>' % base_type 147 if 'R10G10B10A2' in src_format: 148 # When the R10G10B10A2 type can't be used by the vertex buffer, 149 # it needs to be converted to the type which can be used by it. 150 is_signed = 'false' if 'UINT' in src_format or 'UNORM' in src_format or 'USCALED' in src_format else 'true' 151 normalized = 'true' if 'NORM' in src_format else 'false' 152 to_float = 'false' if 'INT' in src_format else 'true' 153 to_half = to_float 154 return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, %s, %s>' % (is_signed, normalized, 155 to_float, to_half) 156 return angle_format.get_vertex_copy_function(src_format, dst_format) 157 158 159def gen_format_case(angle, internal_format, vk_json_data): 160 vk_map = vk_json_data["map"] 161 vk_fallbacks = vk_json_data["fallbacks"] 162 args = dict( 163 format_id=angle, internal_format=internal_format, image_template="", buffer_template="") 164 165 if ((angle not in vk_map) and (angle not in vk_fallbacks)): 166 return empty_format_entry_template.format(**args) 167 168 # get_formats returns override format (if any) + fallbacks 169 # this was necessary to support D32_UNORM. There is no appropriate override that allows 170 # us to fallback to D32_FLOAT, so now we leave the image override empty and function will 171 # give us the fallbacks. 172 def get_formats(format, type): 173 fallbacks = vk_fallbacks.get(format, {}).get(type, []) 174 if not isinstance(fallbacks, list): 175 fallbacks = [fallbacks] 176 177 compressed = vk_fallbacks.get(format, {}).get(type + "_compressed", []) 178 if not isinstance(compressed, list): 179 compressed = [compressed] 180 181 fallbacks += compressed 182 183 if format in vk_map: 184 assert format not in fallbacks 185 fallbacks = [format] + fallbacks 186 187 return (fallbacks, len(fallbacks) - len(compressed)) 188 189 def image_args(format): 190 return dict( 191 image="angle::FormatID::" + format, 192 image_initializer=angle_format.get_internal_format_initializer( 193 internal_format, format)) 194 195 def buffer_args(format): 196 vk_buffer_format = vk_map[format] 197 return dict( 198 buffer="angle::FormatID::" + format, 199 vk_buffer_format_is_packed=is_packed(vk_buffer_format), 200 vertex_load_function=get_vertex_copy_function(angle, format, vk_buffer_format), 201 vertex_load_converts='false' if angle == format else 'true', 202 ) 203 204 images, images_compressed_offset = get_formats(angle, "image") 205 if len(images) == 1: 206 if 'EXTERNAL' in angle: 207 args.update(image_template=image_external_template) 208 else: 209 args.update(image_template=image_basic_template) 210 args.update(image_args(images[0])) 211 elif len(images) > 1: 212 args.update( 213 image_template=image_fallback_template, 214 image_list=", ".join(image_struct_template.format(**image_args(i)) for i in images)) 215 216 buffers, buffers_compressed_offset = get_formats(angle, "buffer") 217 if len(buffers) == 1: 218 args.update(buffer_template=buffer_basic_template) 219 args.update(buffer_args(buffers[0])) 220 elif len(buffers) > 1: 221 args.update( 222 buffer_template=buffer_fallback_template, 223 buffer_list=", ".join( 224 buffer_struct_template.format(**buffer_args(i)) for i in buffers), 225 buffer_compressed_offset=buffers_compressed_offset) 226 227 return format_entry_template.format(**args).format(**args) 228 229 230def get_format_id_case(format_id, vk_format): 231 return "{angle::FormatID::%s, %s}" % (format_id, vk_format) 232 233 234def get_vk_format_case(format_id, vk_format): 235 # don't generate the reverse mapping for the external format slots because they _all_ map 236 # to VK_FORMAT_UNDEFINED and so clash with NONE 237 if 'EXTERNAL' in format_id: 238 return '' 239 return """\ 240 case %s: 241 return angle::FormatID::%s; 242""" % (vk_format, format_id) 243 244 245def main(): 246 247 input_file_name = 'vk_format_map.json' 248 out_file_name = 'vk_format_table_autogen.cpp' 249 250 # auto_script parameters. 251 if len(sys.argv) > 1: 252 inputs = ['../angle_format.py', '../angle_format_map.json', input_file_name] 253 outputs = [out_file_name] 254 255 if sys.argv[1] == 'inputs': 256 print(','.join(inputs)) 257 elif sys.argv[1] == 'outputs': 258 print(','.join(outputs)) 259 else: 260 print('Invalid script parameters') 261 return 1 262 return 0 263 264 angle_to_gl = angle_format.load_inverse_table(os.path.join('..', 'angle_format_map.json')) 265 vk_json_data = angle_format.load_json(input_file_name) 266 267 if not verify_vk_map_keys(angle_to_gl, vk_json_data): 268 return 1 269 270 format_id_cases = [ 271 get_format_id_case(format_id, vk_format) 272 for format_id, vk_format in sorted(vk_json_data["map"].items()) 273 ] 274 275 vk_format_cases = [ 276 get_vk_format_case(format_id, vk_format) 277 for format_id, vk_format in sorted(vk_json_data["map"].items()) 278 ] 279 280 vk_cases = [ 281 gen_format_case(angle, gl, vk_json_data) for angle, gl in sorted(angle_to_gl.items()) 282 ] 283 284 output_cpp = template_table_autogen_cpp.format( 285 format_case_data="\n".join(vk_cases), 286 format_id_cases=",\n".join(format_id_cases), 287 vk_format_cases="".join(vk_format_cases), 288 script_name=os.path.basename(__file__), 289 out_file_name=out_file_name, 290 input_file_name=input_file_name) 291 292 with open(out_file_name, 'wt') as out_file: 293 out_file.write(output_cpp) 294 out_file.close() 295 return 0 296 297 298if __name__ == '__main__': 299 sys.exit(main()) 300