blob: 4e0879a0ca4e24844b172bf5f6bcc1700cbd6aed [file] [log] [blame]
#!/usr/bin/python
# Copyright 2019 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# gen_mtl_format_table.py:
# Code generation for Metal format map.
# NOTE: don't run this script directly. Run scripts/run_code_generation.py.
#
from datetime import date
import json
import math
import pprint
import re
import sys
sys.path.append('..')
import angle_format
template_autogen_inl = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}
//
// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Metal Format table:
// Conversion from ANGLE format to Metal format.
#import <Metal/Metal.h>
#include <TargetConditionals.h>
#include "libANGLE/renderer/Format.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/mtl_format_utils.h"
namespace rx
{{
namespace mtl
{{
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
{{
this->intendedFormatId = intendedFormatId_;
id<MTLDevice> metalDevice = display->getMetalDevice();
// Actual conversion
switch (this->intendedFormatId)
{{
{angle_image_format_switch}
}}
}}
void VertexFormat::init(angle::FormatID angleFormatId, bool tightlyPacked)
{{
this->intendedFormatId = angleFormatId;
// Actual conversion
switch (this->intendedFormatId)
{{
{angle_vertex_format_switch}
}}
}}
}} // namespace mtl
}} // namespace rx
"""
case_image_format_template1 = """ case angle::FormatID::{angle_format}:
this->metalFormat = {mtl_format};
this->actualFormatId = angle::FormatID::{actual_angle_format};
break;
"""
case_image_format_template2 = """ case angle::FormatID::{angle_format}:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{{
this->metalFormat = {mtl_format};
this->actualFormatId = angle::FormatID::{actual_angle_format};
}}
else
{{
this->metalFormat = {mtl_format_fallback};
this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};
}}
break;
"""
case_vertex_format_template1 = """ case angle::FormatID::{angle_format}:
this->metalFormat = {mtl_format};
this->actualFormatId = angle::FormatID::{actual_angle_format};
this->vertexLoadFunction = {vertex_copy_function};
break;
"""
case_vertex_format_template2 = """ case angle::FormatID::{angle_format}:
if (tightlyPacked)
{{
this->metalFormat = {mtl_format_packed};
this->actualFormatId = angle::FormatID::{actual_angle_format_packed};
this->vertexLoadFunction = {vertex_copy_function_packed};
}}
else
{{
this->metalFormat = {mtl_format};
this->actualFormatId = angle::FormatID::{actual_angle_format};
this->vertexLoadFunction = {vertex_copy_function};
}}
break;
"""
def gen_image_map_switch_simple_case(angle_format, actual_angle_format, angle_to_mtl_map):
mtl_format = angle_to_mtl_map[actual_angle_format]
return case_image_format_template1.format(
angle_format=angle_format, actual_angle_format=actual_angle_format, mtl_format=mtl_format)
def gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_mtl_map,
mac_specific_map, mac_fallbacks):
if actual_angle_format in mac_specific_map:
# look for the metal format in mac specific table
mtl_format = mac_specific_map[actual_angle_format]
else:
# look for the metal format in common table
mtl_format = angle_to_mtl_map[actual_angle_format]
if actual_angle_format in mac_fallbacks:
# This format requires fallback when depth24Stencil8PixelFormatSupported flag is false.
# Fallback format:
actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
if actual_angle_format_fallback in mac_specific_map:
# look for the metal format in mac specific table
mtl_format_fallback = mac_specific_map[actual_angle_format_fallback]
else:
# look for the metal format in common table
mtl_format_fallback = angle_to_mtl_map[actual_angle_format_fallback]
# return if else block:
return case_image_format_template2.format(
angle_format=angle_format,
actual_angle_format=actual_angle_format,
mtl_format=mtl_format,
actual_angle_format_fallback=actual_angle_format_fallback,
mtl_format_fallback=mtl_format_fallback)
else:
# return ordinary block:
return case_image_format_template1.format(
angle_format=angle_format,
actual_angle_format=actual_angle_format,
mtl_format=mtl_format)
def gen_image_map_switch_string(image_table):
angle_override = image_table["override"]
mac_override = image_table["override_mac"]
ios_override = image_table["override_ios"]
mac_fallbacks = image_table["fallbacks_mac"]
angle_to_mtl = image_table["map"]
mac_specific_map = image_table["map_mac"]
ios_specific_map = image_table["map_ios"]
switch_data = ''
def gen_image_map_switch_common_case(angle_format, actual_angle_format):
mac_case = gen_image_map_switch_mac_case(angle_format, actual_angle_format, angle_to_mtl,
mac_specific_map, mac_fallbacks)
non_mac_case = gen_image_map_switch_simple_case(angle_format, actual_angle_format,
angle_to_mtl)
if mac_case == non_mac_case:
return mac_case
re = ''
re += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
re += mac_case
re += "#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
re += non_mac_case
re += "#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
return re
# Common case
for angle_format in sorted(angle_to_mtl.keys()):
switch_data += gen_image_map_switch_common_case(angle_format, angle_format)
for angle_format in sorted(angle_override.keys()):
switch_data += gen_image_map_switch_common_case(angle_format, angle_override[angle_format])
# Mac specific
switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
for angle_format in sorted(mac_specific_map.keys()):
switch_data += gen_image_map_switch_mac_case(angle_format, angle_format, angle_to_mtl,
mac_specific_map, mac_fallbacks)
for angle_format in sorted(mac_override.keys()):
# overide case will always map to a format in common table, i.e. angle_to_mtl
switch_data += gen_image_map_switch_mac_case(angle_format, mac_override[angle_format],
angle_to_mtl, mac_specific_map, mac_fallbacks)
# iOS specific
switch_data += "#elif TARGET_OS_IOS // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
for angle_format in sorted(ios_specific_map.keys()):
switch_data += gen_image_map_switch_simple_case(angle_format, angle_format,
ios_specific_map)
for angle_format in sorted(ios_override.keys()):
# overide case will always map to a format in common table, i.e. angle_to_mtl
switch_data += gen_image_map_switch_simple_case(angle_format, ios_override[angle_format],
angle_to_mtl)
switch_data += "#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
switch_data += " default:\n"
switch_data += " this->metalFormat = MTLPixelFormatInvalid;\n"
switch_data += " this->actualFormatId = angle::FormatID::NONE;"
return switch_data
def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map):
mtl_format = angle_to_mtl_map[actual_angle_fmt]
copy_function = angle_format.get_vertex_copy_function(angle_fmt, actual_angle_fmt)
if actual_angle_fmt in override_packed_map:
# This format has an override when used in tightly packed buffer,
# Return if else block
angle_fmt_packed = override_packed_map[actual_angle_fmt]
mtl_format_packed = angle_to_mtl_map[angle_fmt_packed]
copy_function_packed = angle_format.get_vertex_copy_function(angle_fmt, angle_fmt_packed)
return case_vertex_format_template2.format(
angle_format=angle_fmt,
mtl_format_packed=mtl_format_packed,
actual_angle_format_packed=angle_fmt_packed,
vertex_copy_function_packed=copy_function_packed,
mtl_format=mtl_format,
actual_angle_format=actual_angle_fmt,
vertex_copy_function=copy_function)
else:
# This format has no packed buffer's override, return ordinary block.
return case_vertex_format_template1.format(
angle_format=angle_fmt,
mtl_format=mtl_format,
actual_angle_format=actual_angle_fmt,
vertex_copy_function=copy_function)
def gen_vertex_map_switch_string(vertex_table):
angle_to_mtl = vertex_table["map"]
angle_override = vertex_table["override"]
override_packed = vertex_table["override_tightly_packed"]
switch_data = ''
for angle_fmt in sorted(angle_to_mtl.keys()):
switch_data += gen_vertex_map_switch_case(angle_fmt, angle_fmt, angle_to_mtl,
override_packed)
for angle_fmt in sorted(angle_override.keys()):
switch_data += gen_vertex_map_switch_case(angle_fmt, angle_override[angle_fmt],
angle_to_mtl, override_packed)
switch_data += " default:\n"
switch_data += " this->metalFormat = MTLVertexFormatInvalid;\n"
switch_data += " this->actualFormatId = angle::FormatID::NONE;\n"
switch_data += " this->vertexLoadFunction = nullptr;"
return switch_data
def main():
# auto_script parameters.
if len(sys.argv) > 1:
inputs = ['mtl_format_map.json']
outputs = ['mtl_format_table_autogen.mm']
if sys.argv[1] == 'inputs':
print ','.join(inputs)
elif sys.argv[1] == 'outputs':
print ','.join(outputs)
else:
print('Invalid script parameters')
return 1
return 0
data_source_name = 'mtl_format_map.json'
map_json = angle_format.load_json(data_source_name)
map_image = map_json["image"]
map_vertex = map_json["vertex"]
image_switch_data = gen_image_map_switch_string(map_image)
vertex_switch_data = gen_vertex_map_switch_string(map_vertex)
output_cpp = template_autogen_inl.format(
script_name=sys.argv[0],
copyright_year=date.today().year,
data_source_name=data_source_name,
angle_image_format_switch=image_switch_data,
angle_vertex_format_switch=vertex_switch_data)
with open('mtl_format_table_autogen.mm', 'wt') as out_file:
out_file.write(output_cpp)
out_file.close()
if __name__ == '__main__':
sys.exit(main())