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