1#!/usr/bin/python3
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
11import json
12import math
13import pprint
14import re
15import sys
16
17sys.path.append('..')
18import angle_format as angle_format_utils
19
20template_autogen_inl = """// GENERATED FILE - DO NOT EDIT.
21// Generated by {script_name} using data from {data_source_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// Metal Format table:
28//   Conversion from ANGLE format to Metal format.
29
30#import <Metal/Metal.h>
31#include <TargetConditionals.h>
32
33#include "image_util/copyimage.h"
34#include "image_util/generatemip.h"
35#include "image_util/loadimage.h"
36#include "libANGLE/renderer/Format.h"
37#include "libANGLE/renderer/metal/DisplayMtl.h"
38#include "libANGLE/renderer/metal/mtl_format_utils.h"
39
40using namespace angle;
41
42namespace rx
43{{
44namespace mtl
45{{
46
47angle::FormatID Format::MetalToAngleFormatID(MTLPixelFormat formatMtl)
48{{
49    // Actual conversion
50    switch (formatMtl)
51    {{
52{mtl_pixel_format_switch}
53    }}
54}}
55
56void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
57{{
58    this->intendedFormatId = intendedFormatId_;
59
60    id<MTLDevice> metalDevice = display->getMetalDevice();
61
62    // Actual conversion
63    switch (this->intendedFormatId)
64    {{
65{angle_image_format_switch}
66    }}
67}}
68
69void VertexFormat::init(angle::FormatID angleFormatId, bool tightlyPacked)
70{{
71    this->intendedFormatId = angleFormatId;
72
73    // Actual conversion
74    switch (this->intendedFormatId)
75    {{
76{angle_vertex_format_switch}
77    }}
78}}
79
80void FormatTable::initNativeFormatCapsAutogen(const DisplayMtl *display)
81{{
82    const angle::FeaturesMtl &featuresMtl = display->getFeatures();
83    // Skip auto resolve if either hasDepth/StencilAutoResolve or allowMultisampleStoreAndResolve
84    // feature are disabled.
85    bool supportDepthAutoResolve = featuresMtl.hasDepthAutoResolve.enabled &&
86                                   featuresMtl.allowMultisampleStoreAndResolve.enabled;
87    bool supportStencilAutoResolve = featuresMtl.hasStencilAutoResolve.enabled &&
88                                     featuresMtl.allowMultisampleStoreAndResolve.enabled;
89    bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve;
90
91    // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
92    {metal_format_caps}
93}}
94
95}}  // namespace mtl
96}}  // namespace rx
97"""
98
99image_format_assign_template1 = """
100            this->metalFormat = {mtl_format};
101            this->actualFormatId = angle::FormatID::{actual_angle_format};
102            this->initFunction = {init_function};
103"""
104
105image_format_assign_template2 = """
106            if ({fallback_condition})
107            {{
108                this->metalFormat = {mtl_format};
109                this->actualFormatId = angle::FormatID::{actual_angle_format};
110                this->initFunction = {init_function};
111            }}
112            else
113            {{
114                this->metalFormat = {mtl_format_fallback};
115                this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};
116                this->initFunction = {init_function_fallback};
117            }}
118"""
119
120case_image_format_template1 = """        case angle::FormatID::{angle_format}:
121            {image_format_assign}
122            this->swizzled = false;
123            break;
124
125"""
126
127case_image_format_template2 = """        case angle::FormatID::{angle_format}:
128#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
129            if (display->getFeatures().hasTextureSwizzle.enabled)
130            {{
131                {image_format_assign_swizzled}
132                this->swizzled = true;
133                this->swizzle  = {mtl_swizzle};
134            }}
135            else
136#endif  // #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
137            {{
138                {image_format_assign_default}
139                this->swizzled = false;
140            }}
141            break;
142
143"""
144
145case_image_mtl_to_angle_template = """        case {mtl_format}:
146            return angle::FormatID::{angle_format};
147"""
148
149case_vertex_format_template1 = """        case angle::FormatID::{angle_format}:
150            this->metalFormat = {mtl_format};
151            this->actualFormatId = angle::FormatID::{actual_angle_format};
152            this->vertexLoadFunction = {vertex_copy_function};
153            this->defaultAlpha = {default_alpha};
154            this->actualSameGLType = {same_gl_type};
155            break;
156
157"""
158
159case_vertex_format_template2 = """        case angle::FormatID::{angle_format}:
160            if (tightlyPacked)
161            {{
162                this->metalFormat = {mtl_format_packed};
163                this->actualFormatId = angle::FormatID::{actual_angle_format_packed};
164                this->vertexLoadFunction = {vertex_copy_function_packed};
165                this->defaultAlpha = {default_alpha_packed};
166                this->actualSameGLType = {same_gl_type_packed};
167            }}
168            else
169            {{
170                this->metalFormat = {mtl_format};
171                this->actualFormatId = angle::FormatID::{actual_angle_format};
172                this->vertexLoadFunction = {vertex_copy_function};
173                this->defaultAlpha = {default_alpha};
174                this->actualSameGLType = {same_gl_type};
175            }}
176            break;
177
178"""
179
180
181# NOTE(hqle): This is a modified version of the get_vertex_copy_function() function in
182# src/libANGLE/renderer/angle_format.py
183# - Return value is a tuple {copy_function, default_alpha_value, have_same_gl_type}.
184def get_vertex_copy_function_and_default_alpha(src_format, dst_format):
185    if dst_format == "NONE":
186        return "nullptr", 0, "false"
187
188    num_channel = len(angle_format_utils.get_channel_tokens(src_format))
189    if num_channel < 1 or num_channel > 4:
190        return "nullptr", 0, "false"
191
192    src_gl_type = angle_format_utils.get_format_gl_type(src_format)
193    dst_gl_type = angle_format_utils.get_format_gl_type(dst_format)
194
195    if src_gl_type == dst_gl_type:
196        if src_format.startswith('R10G10B10A2'):
197            return 'CopyNativeVertexData<GLuint, 1, 1, 0>', 0, "true"
198
199        if src_gl_type == None:
200            return 'nullptr', 0, "true"
201        dst_num_channel = len(angle_format_utils.get_channel_tokens(dst_format))
202        default_alpha = '1'
203
204        if num_channel == dst_num_channel or dst_num_channel < 4:
205            default_alpha = '0'
206        elif 'A16_FLOAT' in dst_format:
207            default_alpha = 'gl::Float16One'
208        elif 'A32_FLOAT' in dst_format:
209            default_alpha = 'gl::Float32One'
210        elif 'NORM' in dst_format:
211            default_alpha = 'std::numeric_limits<%s>::max()' % (src_gl_type)
212
213        return 'CopyNativeVertexData<%s, %d, %d, %s>' % (src_gl_type, num_channel, dst_num_channel,
214                                                         default_alpha), default_alpha, "true"
215
216    if src_format.startswith('R10G10B10A2'):
217        assert 'FLOAT' in dst_format, ('get_vertex_copy_function: can only convert to float,' +
218                                       ' not to ' + dst_format)
219        is_signed = 'true' if 'SINT' in src_format or 'SNORM' in src_format or 'SSCALED' in src_format else 'false'
220        is_normal = 'true' if 'NORM' in src_format else 'false'
221        return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, true, false>' % (is_signed,
222                                                                          is_normal), 0, "false"
223
224    return angle_format_utils.get_vertex_copy_function(src_format, dst_format), 0, "false"
225
226
227# Generate format conversion switch case (generic case)
228def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
229                              assign_gen_func):
230    if isinstance(actual_angle_format_info, dict):
231        default_actual_angle_format = actual_angle_format_info['default']
232        # Check if the format can be override with swizzle feature
233        if 'swizzle' in actual_angle_format_info:
234            swizzle_info = actual_angle_format_info['swizzle']
235            swizzle_channels = swizzle_info[0]
236            swizzled_actual_angle_format = swizzle_info[1]
237            swizzle_map = {
238                'R': 'GL_RED',
239                'G': 'GL_GREEN',
240                'B': 'GL_BLUE',
241                'A': 'GL_ALPHA',
242                '1': 'GL_ONE',
243                '0': 'GL_ZERO',
244            }
245
246            mtl_swizzle_make = '{{{r}, {g}, {b}, {a}}}'.format(
247                r=swizzle_map[swizzle_channels[0:1]],
248                g=swizzle_map[swizzle_channels[1:2]],
249                b=swizzle_map[swizzle_channels[2:3]],
250                a=swizzle_map[swizzle_channels[3:]])
251            return case_image_format_template2.format(
252                angle_format=angle_format,
253                image_format_assign_default=assign_gen_func(default_actual_angle_format,
254                                                            angle_to_mtl_map),
255                image_format_assign_swizzled=assign_gen_func(swizzled_actual_angle_format,
256                                                             angle_to_mtl_map),
257                mtl_swizzle=mtl_swizzle_make)
258        else:
259            # Only default case
260            return gen_image_map_switch_case(angle_format, default_actual_angle_format,
261                                             angle_to_mtl_map, assign_gen_func)
262    else:
263        # Default case
264        return case_image_format_template1.format(
265            angle_format=angle_format,
266            image_format_assign=assign_gen_func(actual_angle_format_info, angle_to_mtl_map))
267
268
269# Generate format conversion switch case (simple case)
270def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
271                                     angle_to_mtl_map):
272
273    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
274        return image_format_assign_template1.format(
275            actual_angle_format=actual_angle_format,
276            mtl_format=angle_to_mtl_map[actual_angle_format],
277            init_function=angle_format_utils.get_internal_format_initializer(
278                angle_to_gl[angle_format], actual_angle_format))
279
280    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
281                                     gen_format_assign_code)
282
283
284# Generate format conversion switch case (Mac case)
285def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
286                                  angle_to_mtl_map, mac_fallbacks):
287    gl_format = angle_to_gl[angle_format]
288
289    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
290        if actual_angle_format in mac_fallbacks:
291            # This format requires fallback when depth24Stencil8PixelFormatSupported flag is false.
292            # Fallback format:
293            actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
294            fallback_condition = "metalDevice.depth24Stencil8PixelFormatSupported && \
295                                 !display->getFeatures().forceD24S8AsUnsupported.enabled"
296            # return if else block:
297            return image_format_assign_template2.format(
298                actual_angle_format=actual_angle_format,
299                mtl_format=angle_to_mtl_map[actual_angle_format],
300                init_function=angle_format_utils.get_internal_format_initializer(
301                    gl_format, actual_angle_format),
302                actual_angle_format_fallback=actual_angle_format_fallback,
303                mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
304                init_function_fallback=angle_format_utils.get_internal_format_initializer(
305                    gl_format, actual_angle_format_fallback),
306                fallback_condition=fallback_condition)
307        else:
308            # return ordinary block:
309            return image_format_assign_template1.format(
310                actual_angle_format=actual_angle_format,
311                mtl_format=angle_to_mtl_map[actual_angle_format],
312                init_function=angle_format_utils.get_internal_format_initializer(
313                    gl_format, actual_angle_format))
314
315    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
316                                     gen_format_assign_code)
317
318
319# Generate format conversion switch case (non-desktop ES 3.0 case)
320def gen_image_map_switch_es3_case(angle_format, actual_angle_format_info, angle_to_gl,
321                                  angle_to_mtl_map, mac_fallbacks):
322    gl_format = angle_to_gl[angle_format]
323
324    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
325        actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
326        return image_format_assign_template2.format(
327            actual_angle_format=actual_angle_format,
328            mtl_format=angle_to_mtl_map[actual_angle_format],
329            init_function=angle_format_utils.get_internal_format_initializer(
330                gl_format, actual_angle_format),
331            actual_angle_format_fallback=actual_angle_format_fallback,
332            mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
333            init_function_fallback=angle_format_utils.get_internal_format_initializer(
334                gl_format, actual_angle_format_fallback),
335            fallback_condition="display->supportsAppleGPUFamily(1)")
336
337    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
338                                     gen_format_assign_code)
339
340
341# Generate format conversion switch case (ASTC LDR/HDR case)
342def gen_image_map_switch_astc_case(angle_format, angle_to_gl, angle_to_mtl_map):
343    gl_format = angle_to_gl[angle_format]
344
345    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
346        return image_format_assign_template2.format(
347            actual_angle_format=actual_angle_format,
348            mtl_format=angle_to_mtl_map[actual_angle_format] + "HDR",
349            init_function=angle_format_utils.get_internal_format_initializer(
350                gl_format, actual_angle_format),
351            actual_angle_format_fallback=actual_angle_format,
352            mtl_format_fallback=angle_to_mtl_map[actual_angle_format] + "LDR",
353            init_function_fallback=angle_format_utils.get_internal_format_initializer(
354                gl_format, actual_angle_format),
355            fallback_condition="display->supportsAppleGPUFamily(6)")
356
357    return gen_image_map_switch_case(angle_format, angle_format, angle_to_mtl_map,
358                                     gen_format_assign_code)
359
360
361def gen_image_map_switch_string(image_table, angle_to_gl):
362    angle_override = image_table["override"]
363    mac_override_es3 = image_table["override_mac_es3"]
364    mac_override_bc1 = image_table["override_mac_bc1"]
365    ios_override = image_table["override_ios"]
366    mac_d24s8_fallbacks = image_table["d24s8_fallbacks_mac"]
367    angle_to_mtl = image_table["map"]
368    mac_specific_map = image_table["map_mac"]
369    ios_specific_map = image_table["map_ios"]
370    astc_tpl_map = image_table["map_astc_tpl"]
371
372    # mac_specific_map + angle_to_mtl:
373    mac_angle_to_mtl = mac_specific_map.copy()
374    mac_angle_to_mtl.update(angle_to_mtl)
375    # ios_specific_map + angle_to_mtl
376    ios_angle_to_mtl = ios_specific_map.copy()
377    ios_angle_to_mtl.update(angle_to_mtl)
378
379    switch_data = ''
380
381    def gen_image_map_switch_common_case(angle_format, actual_angle_format):
382        return gen_image_map_switch_simple_case(angle_format, actual_angle_format, angle_to_gl,
383                                                angle_to_mtl)
384
385    # Common case: universally-supported formats + universal overrides
386    for angle_format in sorted(angle_to_mtl.keys()):
387        switch_data += gen_image_map_switch_common_case(angle_format, angle_format)
388    for angle_format in sorted(angle_override.keys()):
389        switch_data += gen_image_map_switch_common_case(angle_format, angle_override[angle_format])
390
391    # Mac GPU case: macOS + Catalyst targets
392    switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
393    for angle_format in sorted(mac_specific_map.keys()):
394        switch_data += gen_image_map_switch_mac_case(angle_format, angle_format, angle_to_gl,
395                                                     mac_angle_to_mtl, mac_d24s8_fallbacks)
396    for angle_format in sorted(mac_override_bc1.keys()):
397        switch_data += gen_image_map_switch_simple_case(angle_format,
398                                                        mac_override_bc1[angle_format],
399                                                        angle_to_gl, mac_angle_to_mtl)
400    switch_data += "#endif\n"
401
402    # Override missing ES 3.0 formats for older macOS SDK or Catalyst
403    switch_data += "#if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED < 101600)) || \\\n"
404    switch_data += "TARGET_OS_MACCATALYST\n"
405    for angle_format in sorted(mac_override_es3.keys()):
406        switch_data += gen_image_map_switch_simple_case(angle_format,
407                                                        mac_override_es3[angle_format],
408                                                        angle_to_gl, mac_angle_to_mtl)
409    switch_data += "#endif\n"
410
411    # iOS specific
412    switch_data += "#if TARGET_OS_IOS || TARGET_OS_TV\n"
413    for angle_format in sorted(ios_specific_map.keys()):
414        switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, angle_to_gl,
415                                                        ios_specific_map)
416    for angle_format in sorted(ios_override.keys()):
417        switch_data += gen_image_map_switch_simple_case(angle_format, ios_override[angle_format],
418                                                        angle_to_gl, ios_angle_to_mtl)
419    for angle_format in sorted(astc_tpl_map.keys()):
420        switch_data += gen_image_map_switch_astc_case(angle_format, angle_to_gl, astc_tpl_map)
421    switch_data += "#endif\n"
422
423    # Try to support all iOS formats on newer macOS with Apple GPU.
424    switch_data += "#if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600))\n"
425    for angle_format in sorted(ios_specific_map.keys()):
426        if (angle_format in mac_override_es3.keys()):
427            # ETC/EAC or packed 16-bit
428            switch_data += gen_image_map_switch_es3_case(angle_format, angle_format, angle_to_gl,
429                                                         ios_angle_to_mtl, mac_override_es3)
430        else:
431            # ASTC sRGB or PVRTC1
432            switch_data += gen_image_map_switch_simple_case(angle_format, angle_format,
433                                                            angle_to_gl, ios_specific_map)
434    # ASTC LDR or HDR
435    for angle_format in sorted(astc_tpl_map.keys()):
436        switch_data += gen_image_map_switch_astc_case(angle_format, angle_to_gl, astc_tpl_map)
437    switch_data += "#endif\n"
438
439    switch_data += "        default:\n"
440    switch_data += "            this->metalFormat = MTLPixelFormatInvalid;\n"
441    switch_data += "            this->actualFormatId = angle::FormatID::NONE;"
442    return switch_data
443
444
445def gen_image_mtl_to_angle_switch_string(image_table):
446    angle_to_mtl = image_table["map"]
447    mac_specific_map = image_table["map_mac"]
448    ios_specific_map = image_table["map_ios"]
449    astc_tpl_map = image_table["map_astc_tpl"]
450
451    switch_data = ''
452
453    # Common case
454    for angle_format in sorted(angle_to_mtl.keys()):
455        switch_data += case_image_mtl_to_angle_template.format(
456            mtl_format=angle_to_mtl[angle_format], angle_format=angle_format)
457
458    # Mac specific
459    switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
460    for angle_format in sorted(mac_specific_map.keys()):
461        switch_data += case_image_mtl_to_angle_template.format(
462            mtl_format=mac_specific_map[angle_format], angle_format=angle_format)
463    switch_data += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
464
465    # iOS + macOS 11.0+ specific
466    switch_data += "#if TARGET_OS_IOS || TARGET_OS_TV || (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600))\n"
467    for angle_format in sorted(ios_specific_map.keys()):
468        # ETC1_R8G8B8_UNORM_BLOCK is a duplicated of ETC2_R8G8B8_UNORM_BLOCK
469        if angle_format == 'ETC1_R8G8B8_UNORM_BLOCK':
470            continue
471        switch_data += case_image_mtl_to_angle_template.format(
472            mtl_format=ios_specific_map[angle_format], angle_format=angle_format)
473    for angle_format in sorted(astc_tpl_map.keys()):
474        switch_data += case_image_mtl_to_angle_template.format(
475            mtl_format=astc_tpl_map[angle_format] + "LDR", angle_format=angle_format)
476        switch_data += case_image_mtl_to_angle_template.format(
477            mtl_format=astc_tpl_map[angle_format] + "HDR", angle_format=angle_format)
478    switch_data += "#endif  // TARGET_OS_IOS || TARGET_OS_TV || mac 11.0+\n"
479
480    switch_data += "        default:\n"
481    switch_data += "            return angle::FormatID::NONE;\n"
482    return switch_data
483
484
485def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map):
486    mtl_format = angle_to_mtl_map[actual_angle_fmt]
487    copy_function, default_alpha, same_gl_type = get_vertex_copy_function_and_default_alpha(
488        angle_fmt, actual_angle_fmt)
489
490    if actual_angle_fmt in override_packed_map:
491        # This format has an override when used in tightly packed buffer,
492        # Return if else block
493        angle_fmt_packed = override_packed_map[actual_angle_fmt]
494        mtl_format_packed = angle_to_mtl_map[angle_fmt_packed]
495        copy_function_packed, default_alpha_packed, same_gl_type_packed = get_vertex_copy_function_and_default_alpha(
496            angle_fmt, angle_fmt_packed)
497
498        return case_vertex_format_template2.format(
499            angle_format=angle_fmt,
500            mtl_format_packed=mtl_format_packed,
501            actual_angle_format_packed=angle_fmt_packed,
502            vertex_copy_function_packed=copy_function_packed,
503            default_alpha_packed=default_alpha_packed,
504            same_gl_type_packed=same_gl_type_packed,
505            mtl_format=mtl_format,
506            actual_angle_format=actual_angle_fmt,
507            vertex_copy_function=copy_function,
508            default_alpha=default_alpha,
509            same_gl_type=same_gl_type)
510    else:
511        # This format has no packed buffer's override, return ordinary block.
512        return case_vertex_format_template1.format(
513            angle_format=angle_fmt,
514            mtl_format=mtl_format,
515            actual_angle_format=actual_angle_fmt,
516            vertex_copy_function=copy_function,
517            default_alpha=default_alpha,
518            same_gl_type=same_gl_type)
519
520
521def gen_vertex_map_switch_string(vertex_table):
522    angle_to_mtl = vertex_table["map"]
523    angle_override = vertex_table["override"]
524    override_packed = vertex_table["override_tightly_packed"]
525
526    switch_data = ''
527    for angle_fmt in sorted(angle_to_mtl.keys()):
528        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_fmt, angle_to_mtl,
529                                                  override_packed)
530
531    for angle_fmt in sorted(angle_override.keys()):
532        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_override[angle_fmt],
533                                                  angle_to_mtl, override_packed)
534
535    switch_data += "        default:\n"
536    switch_data += "            this->metalFormat = MTLVertexFormatInvalid;\n"
537    switch_data += "            this->actualFormatId = angle::FormatID::NONE;\n"
538    switch_data += "            this->vertexLoadFunction = nullptr;"
539    switch_data += "            this->defaultAlpha = 0;"
540    switch_data += "            this->actualSameGLType = false;"
541    return switch_data
542
543
544def gen_mtl_format_caps_init_string(map_image):
545    caps = map_image['caps']
546    mac_caps = map_image['caps_mac']
547    ios_caps = map_image['caps_ios']
548    caps_init_str = ''
549
550    def cap_to_param(caps, key):
551        return '/** ' + key + '*/ ' + caps.get(key, 'false')
552
553    def caps_to_cpp(caps_table):
554        init_str = ''
555        for mtl_format in sorted(caps_table.keys()):
556            caps = caps_table[mtl_format]
557            filterable = cap_to_param(caps, 'filterable')
558            writable = cap_to_param(caps, 'writable')
559            colorRenderable = cap_to_param(caps, 'colorRenderable')
560            depthRenderable = cap_to_param(caps, 'depthRenderable')
561            blendable = cap_to_param(caps, 'blendable')
562            multisample = cap_to_param(caps, 'multisample')
563            resolve = cap_to_param(caps, 'resolve')
564
565            init_str += "    setFormatCaps({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7});\n\n".format(
566                mtl_format, filterable, writable, blendable, multisample, resolve, colorRenderable,
567                depthRenderable)
568
569        return init_str
570
571    caps_init_str += caps_to_cpp(caps)
572
573    caps_init_str += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
574    caps_init_str += caps_to_cpp(mac_caps)
575    caps_init_str += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
576
577    caps_init_str += "#if (TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || TARGET_OS_TV || \\\n"
578    caps_init_str += "    (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600))\n"
579
580    caps_init_str += caps_to_cpp(ios_caps)
581
582    caps_init_str += "#endif\n"
583
584    return caps_init_str
585
586
587def main():
588    data_source_name = 'mtl_format_map.json'
589    # auto_script parameters.
590    if len(sys.argv) > 1:
591        inputs = ['../angle_format.py', '../angle_format_map.json', data_source_name]
592        outputs = ['mtl_format_table_autogen.mm']
593
594        if sys.argv[1] == 'inputs':
595            print(','.join(inputs))
596        elif sys.argv[1] == 'outputs':
597            print(','.join(outputs))
598        else:
599            print('Invalid script parameters')
600            return 1
601        return 0
602
603    angle_to_gl = angle_format_utils.load_inverse_table('../angle_format_map.json')
604
605    map_json = angle_format_utils.load_json(data_source_name)
606    map_image = map_json["image"]
607    map_vertex = map_json["vertex"]
608
609    image_switch_data = gen_image_map_switch_string(map_image, angle_to_gl)
610    image_mtl_to_angle_switch_data = gen_image_mtl_to_angle_switch_string(map_image)
611
612    vertex_switch_data = gen_vertex_map_switch_string(map_vertex)
613
614    caps_init_str = gen_mtl_format_caps_init_string(map_image)
615
616    output_cpp = template_autogen_inl.format(
617        script_name=sys.argv[0],
618        data_source_name=data_source_name,
619        angle_image_format_switch=image_switch_data,
620        mtl_pixel_format_switch=image_mtl_to_angle_switch_data,
621        angle_vertex_format_switch=vertex_switch_data,
622        metal_format_caps=caps_init_str)
623    with open('mtl_format_table_autogen.mm', 'wt') as out_file:
624        out_file.write(output_cpp)
625        out_file.close()
626
627
628if __name__ == '__main__':
629    sys.exit(main())
630