1#!/usr/bin/python 2# Copyright 2019 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_mtl_format_table.py: 7# Code generation for Metal format map. 8# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 9# 10 11from datetime import date 12import json 13import math 14import pprint 15import re 16import sys 17 18sys.path.append('..') 19import angle_format 20 21template_autogen_inl = """// GENERATED FILE - DO NOT EDIT. 22// Generated by {script_name} using data from {data_source_name} 23// 24// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved. 25// Use of this source code is governed by a BSD-style license that can be 26// found in the LICENSE file. 27// 28// Metal Format table: 29// Conversion from ANGLE format to Metal format. 30 31#import <Metal/Metal.h> 32#include <TargetConditionals.h> 33 34#include "libANGLE/renderer/Format.h" 35#include "libANGLE/renderer/metal/DisplayMtl.h" 36#include "libANGLE/renderer/metal/mtl_format_utils.h" 37 38namespace rx 39{{ 40namespace mtl 41{{ 42 43void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) 44{{ 45 this->intendedFormatId = intendedFormatId_; 46 47 id<MTLDevice> metalDevice = display->getMetalDevice(); 48 49 // Actual conversion 50 switch (this->intendedFormatId) 51 {{ 52{angle_image_format_switch} 53 }} 54}} 55 56void VertexFormat::init(angle::FormatID angleFormatId, bool tightlyPacked) 57{{ 58 this->intendedFormatId = angleFormatId; 59 60 // Actual conversion 61 switch (this->intendedFormatId) 62 {{ 63{angle_vertex_format_switch} 64 }} 65}} 66 67}} // namespace mtl 68}} // namespace rx 69""" 70 71case_image_format_template1 = """ case angle::FormatID::{angle_format}: 72 this->metalFormat = {mtl_format}; 73 this->actualFormatId = angle::FormatID::{actual_angle_format}; 74 break; 75 76""" 77 78case_image_format_template2 = """ case angle::FormatID::{angle_format}: 79 if (metalDevice.depth24Stencil8PixelFormatSupported) 80 {{ 81 this->metalFormat = {mtl_format}; 82 this->actualFormatId = angle::FormatID::{actual_angle_format}; 83 }} 84 else 85 {{ 86 this->metalFormat = {mtl_format_fallback}; 87 this->actualFormatId = angle::FormatID::{actual_angle_format_fallback}; 88 }} 89 break; 90 91""" 92 93case_vertex_format_template1 = """ case angle::FormatID::{angle_format}: 94 this->metalFormat = {mtl_format}; 95 this->actualFormatId = angle::FormatID::{actual_angle_format}; 96 this->vertexLoadFunction = {vertex_copy_function}; 97 break; 98 99""" 100 101case_vertex_format_template2 = """ case angle::FormatID::{angle_format}: 102 if (tightlyPacked) 103 {{ 104 this->metalFormat = {mtl_format_packed}; 105 this->actualFormatId = angle::FormatID::{actual_angle_format_packed}; 106 this->vertexLoadFunction = {vertex_copy_function_packed}; 107 }} 108 else 109 {{ 110 this->metalFormat = {mtl_format}; 111 this->actualFormatId = angle::FormatID::{actual_angle_format}; 112 this->vertexLoadFunction = {vertex_copy_function}; 113 }} 114 break; 115 116""" 117 118 119def gen_image_map_switch_simple_case(angle_format, actual_angle_format, angle_to_mtl_map): 120 mtl_format = angle_to_mtl_map[actual_angle_format] 121 return case_image_format_template1.format( 122 angle_format=angle_format, actual_angle_format=actual_angle_format, mtl_format=mtl_format) 123 124 125def gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_mtl_map, 126 mac_specific_map, mac_fallbacks): 127 if actual_angle_format in mac_specific_map: 128 # look for the metal format in mac specific table 129 mtl_format = mac_specific_map[actual_angle_format] 130 else: 131 # look for the metal format in common table 132 mtl_format = angle_to_mtl_map[actual_angle_format] 133 134 if actual_angle_format in mac_fallbacks: 135 # This format requires fallback when depth24Stencil8PixelFormatSupported flag is false. 136 # Fallback format: 137 actual_angle_format_fallback = mac_fallbacks[actual_angle_format] 138 if actual_angle_format_fallback in mac_specific_map: 139 # look for the metal format in mac specific table 140 mtl_format_fallback = mac_specific_map[actual_angle_format_fallback] 141 else: 142 # look for the metal format in common table 143 mtl_format_fallback = angle_to_mtl_map[actual_angle_format_fallback] 144 # return if else block: 145 return case_image_format_template2.format( 146 angle_format=angle_format, 147 actual_angle_format=actual_angle_format, 148 mtl_format=mtl_format, 149 actual_angle_format_fallback=actual_angle_format_fallback, 150 mtl_format_fallback=mtl_format_fallback) 151 else: 152 # return ordinary block: 153 return case_image_format_template1.format( 154 angle_format=angle_format, 155 actual_angle_format=actual_angle_format, 156 mtl_format=mtl_format) 157 158 159def gen_image_map_switch_string(image_table): 160 angle_override = image_table["override"] 161 mac_override = image_table["override_mac"] 162 ios_override = image_table["override_ios"] 163 mac_fallbacks = image_table["fallbacks_mac"] 164 angle_to_mtl = image_table["map"] 165 mac_specific_map = image_table["map_mac"] 166 ios_specific_map = image_table["map_ios"] 167 168 switch_data = '' 169 170 def gen_image_map_switch_common_case(angle_format, actual_angle_format): 171 mac_case = gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_mtl, 172 mac_specific_map, mac_fallbacks) 173 non_mac_case = gen_image_map_switch_simple_case(angle_format, actual_angle_format, 174 angle_to_mtl) 175 if mac_case == non_mac_case: 176 return mac_case 177 178 re = '' 179 re += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 180 re += mac_case 181 re += "#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 182 re += non_mac_case 183 re += "#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 184 return re 185 186 # Common case 187 for angle_format in sorted(angle_to_mtl.keys()): 188 switch_data += gen_image_map_switch_common_case(angle_format, angle_format) 189 for angle_format in sorted(angle_override.keys()): 190 switch_data += gen_image_map_switch_common_case(angle_format, angle_override[angle_format]) 191 192 # Mac specific 193 switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 194 for angle_format in sorted(mac_specific_map.keys()): 195 switch_data += gen_image_map_switch_mac_case(angle_format, angle_format, angle_to_mtl, 196 mac_specific_map, mac_fallbacks) 197 for angle_format in sorted(mac_override.keys()): 198 # overide case will always map to a format in common table, i.e. angle_to_mtl 199 switch_data += gen_image_map_switch_mac_case(angle_format, mac_override[angle_format], 200 angle_to_mtl, mac_specific_map, mac_fallbacks) 201 202 # iOS specific 203 switch_data += "#elif TARGET_OS_IOS // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 204 for angle_format in sorted(ios_specific_map.keys()): 205 switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, 206 ios_specific_map) 207 for angle_format in sorted(ios_override.keys()): 208 # overide case will always map to a format in common table, i.e. angle_to_mtl 209 switch_data += gen_image_map_switch_simple_case(angle_format, ios_override[angle_format], 210 angle_to_mtl) 211 switch_data += "#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n" 212 switch_data += " default:\n" 213 switch_data += " this->metalFormat = MTLPixelFormatInvalid;\n" 214 switch_data += " this->actualFormatId = angle::FormatID::NONE;" 215 return switch_data 216 217 218def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map): 219 mtl_format = angle_to_mtl_map[actual_angle_fmt] 220 copy_function = angle_format.get_vertex_copy_function(angle_fmt, actual_angle_fmt) 221 if actual_angle_fmt in override_packed_map: 222 # This format has an override when used in tightly packed buffer, 223 # Return if else block 224 angle_fmt_packed = override_packed_map[actual_angle_fmt] 225 mtl_format_packed = angle_to_mtl_map[angle_fmt_packed] 226 copy_function_packed = angle_format.get_vertex_copy_function(angle_fmt, angle_fmt_packed) 227 return case_vertex_format_template2.format( 228 angle_format=angle_fmt, 229 mtl_format_packed=mtl_format_packed, 230 actual_angle_format_packed=angle_fmt_packed, 231 vertex_copy_function_packed=copy_function_packed, 232 mtl_format=mtl_format, 233 actual_angle_format=actual_angle_fmt, 234 vertex_copy_function=copy_function) 235 else: 236 # This format has no packed buffer's override, return ordinary block. 237 return case_vertex_format_template1.format( 238 angle_format=angle_fmt, 239 mtl_format=mtl_format, 240 actual_angle_format=actual_angle_fmt, 241 vertex_copy_function=copy_function) 242 243 244def gen_vertex_map_switch_string(vertex_table): 245 angle_to_mtl = vertex_table["map"] 246 angle_override = vertex_table["override"] 247 override_packed = vertex_table["override_tightly_packed"] 248 249 switch_data = '' 250 for angle_fmt in sorted(angle_to_mtl.keys()): 251 switch_data += gen_vertex_map_switch_case(angle_fmt, angle_fmt, angle_to_mtl, 252 override_packed) 253 254 for angle_fmt in sorted(angle_override.keys()): 255 switch_data += gen_vertex_map_switch_case(angle_fmt, angle_override[angle_fmt], 256 angle_to_mtl, override_packed) 257 258 switch_data += " default:\n" 259 switch_data += " this->metalFormat = MTLVertexFormatInvalid;\n" 260 switch_data += " this->actualFormatId = angle::FormatID::NONE;\n" 261 switch_data += " this->vertexLoadFunction = nullptr;" 262 return switch_data 263 264 265def main(): 266 # auto_script parameters. 267 if len(sys.argv) > 1: 268 inputs = ['../angle_format.py', 'mtl_format_map.json'] 269 outputs = ['mtl_format_table_autogen.mm'] 270 271 if sys.argv[1] == 'inputs': 272 print ','.join(inputs) 273 elif sys.argv[1] == 'outputs': 274 print ','.join(outputs) 275 else: 276 print('Invalid script parameters') 277 return 1 278 return 0 279 280 data_source_name = 'mtl_format_map.json' 281 map_json = angle_format.load_json(data_source_name) 282 map_image = map_json["image"] 283 map_vertex = map_json["vertex"] 284 285 image_switch_data = gen_image_map_switch_string(map_image) 286 287 vertex_switch_data = gen_vertex_map_switch_string(map_vertex) 288 289 output_cpp = template_autogen_inl.format( 290 script_name=sys.argv[0], 291 copyright_year=date.today().year, 292 data_source_name=data_source_name, 293 angle_image_format_switch=image_switch_data, 294 angle_vertex_format_switch=vertex_switch_data) 295 with open('mtl_format_table_autogen.mm', 'wt') as out_file: 296 out_file.write(output_cpp) 297 out_file.close() 298 299 300if __name__ == '__main__': 301 sys.exit(main()) 302