xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/gen_mtl_format_table.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 (display->getFeatures().hasTextureSwizzle.enabled)
147            {{
148                {image_format_assign_swizzled}
149                this->swizzled = true;
150                this->swizzle  = {mtl_swizzle};
151            }}
152            else
153            {{
154                {image_format_assign_default}
155            }}
156            break;
157
158"""
159
160case_image_mtl_to_angle_template = """        case {mtl_format}:
161            return angle::FormatID::{angle_format};
162"""
163
164case_vertex_format_template1 = """        case angle::FormatID::{angle_format}:
165            this->metalFormat = {mtl_format};
166            this->actualFormatId = angle::FormatID::{actual_angle_format};
167            this->vertexLoadFunction = {vertex_copy_function};
168            this->defaultAlpha = {default_alpha};{same_gl_type}
169            break;
170
171"""
172
173case_vertex_format_template2 = """        case angle::FormatID::{angle_format}:
174            if (tightlyPacked)
175            {{
176                this->metalFormat = {mtl_format_packed};
177                this->actualFormatId = angle::FormatID::{actual_angle_format_packed};
178                this->vertexLoadFunction = {vertex_copy_function_packed};
179                this->defaultAlpha = {default_alpha_packed};{same_gl_type_packed}
180            }}
181            else
182            {{
183                this->metalFormat = {mtl_format};
184                this->actualFormatId = angle::FormatID::{actual_angle_format};
185                this->vertexLoadFunction = {vertex_copy_function};
186                this->defaultAlpha = {default_alpha};{same_gl_type}
187            }}
188            break;
189
190"""
191
192
193def wrap_init_function(str):
194    return '' if str == 'nullptr' else f'this->initFunction = {str};'
195
196
197def wrap_actual_same_gl_type(str):
198    return '' if str == 'true' else f'this->actualSameGLType = {str};'
199
200
201# NOTE(hqle): This is a modified version of the get_vertex_copy_function() function in
202# src/libANGLE/renderer/angle_format.py
203# - Return value is a tuple {copy_function, default_alpha_value, have_same_gl_type}.
204def get_vertex_copy_function_and_default_alpha(src_format, dst_format):
205    if dst_format == "NONE":
206        return "nullptr", 0, "false"
207
208    num_channel = len(angle_format_utils.get_channel_tokens(src_format))
209    if num_channel < 1 or num_channel > 4:
210        return "nullptr", 0, "false"
211
212    src_gl_type = angle_format_utils.get_format_gl_type(src_format)
213    dst_gl_type = angle_format_utils.get_format_gl_type(dst_format)
214
215    if src_gl_type == dst_gl_type:
216        if src_format.startswith('R10G10B10A2'):
217            return 'CopyNativeVertexData<GLuint, 1, 1, 0>', 0, "true"
218
219        if src_gl_type == None:
220            return 'nullptr', 0, "true"
221        dst_num_channel = len(angle_format_utils.get_channel_tokens(dst_format))
222        default_alpha = '1'
223
224        if num_channel == dst_num_channel or dst_num_channel < 4:
225            default_alpha = '0'
226        elif 'A16_FLOAT' in dst_format:
227            default_alpha = 'gl::Float16One'
228        elif 'A32_FLOAT' in dst_format:
229            default_alpha = 'gl::Float32One'
230        elif 'NORM' in dst_format:
231            default_alpha = 'std::numeric_limits<%s>::max()' % (src_gl_type)
232
233        return 'CopyNativeVertexData<%s, %d, %d, %s>' % (src_gl_type, num_channel, dst_num_channel,
234                                                         default_alpha), default_alpha, "true"
235
236    if src_format.startswith('R10G10B10A2'):
237        assert 'FLOAT' in dst_format, ('get_vertex_copy_function: can only convert to float,' +
238                                       ' not to ' + dst_format)
239        is_signed = 'true' if 'SINT' in src_format or 'SNORM' in src_format or 'SSCALED' in src_format else 'false'
240        is_normal = 'true' if 'NORM' in src_format else 'false'
241        return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, true, false>' % (is_signed,
242                                                                          is_normal), 0, "false"
243
244    return angle_format_utils.get_vertex_copy_function(src_format, dst_format), 0, "false"
245
246
247# Generate format conversion switch case (generic case)
248
249
250def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
251                              assign_gen_func):
252    if isinstance(actual_angle_format_info, dict):
253        default_actual_angle_format = actual_angle_format_info['default']
254        # Check if the format can be override with swizzle feature
255        if 'swizzle' in actual_angle_format_info:
256            swizzle_info = actual_angle_format_info['swizzle']
257            swizzle_channels = swizzle_info[0]
258            swizzled_actual_angle_format = swizzle_info[1]
259            swizzle_map = {
260                'R': 'GL_RED',
261                'G': 'GL_GREEN',
262                'B': 'GL_BLUE',
263                'A': 'GL_ALPHA',
264                '1': 'GL_ONE',
265                '0': 'GL_ZERO',
266            }
267
268            mtl_swizzle_make = '{{{r}, {g}, {b}, {a}}}'.format(
269                r=swizzle_map[swizzle_channels[0:1]],
270                g=swizzle_map[swizzle_channels[1:2]],
271                b=swizzle_map[swizzle_channels[2:3]],
272                a=swizzle_map[swizzle_channels[3:]])
273            return case_image_format_template2.format(
274                angle_format=angle_format,
275                image_format_assign_default=assign_gen_func(default_actual_angle_format,
276                                                            angle_to_mtl_map),
277                image_format_assign_swizzled=assign_gen_func(swizzled_actual_angle_format,
278                                                             angle_to_mtl_map),
279                mtl_swizzle=mtl_swizzle_make)
280        else:
281            # Only default case
282            return gen_image_map_switch_case(angle_format, default_actual_angle_format,
283                                             angle_to_mtl_map, assign_gen_func)
284    else:
285        # Default case
286        return case_image_format_template1.format(
287            angle_format=angle_format,
288            image_format_assign=assign_gen_func(actual_angle_format_info, angle_to_mtl_map))
289
290
291# Generate format conversion switch case (simple case)
292
293
294def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
295                                     angle_to_mtl_map):
296
297    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
298        return image_format_assign_template1.format(
299            actual_angle_format=actual_angle_format,
300            mtl_format=angle_to_mtl_map[actual_angle_format],
301            init_function=wrap_init_function(
302                angle_format_utils.get_internal_format_initializer(angle_to_gl[angle_format],
303                                                                   actual_angle_format)))
304
305    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
306                                     gen_format_assign_code)
307
308
309# Generate format conversion switch case (Mac case)
310
311
312def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
313                                  angle_to_mtl_map, mac_fallbacks):
314    gl_format = angle_to_gl[angle_format]
315
316    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
317        if actual_angle_format in mac_fallbacks:
318            # This format requires fallback when depth24Stencil8PixelFormatSupported flag is false.
319            # Fallback format:
320            actual_angle_format_fallback = mac_fallbacks[actual_angle_format]["format"]
321            fallback_condition = mac_fallbacks[actual_angle_format]["condition"]
322            # return if else block:
323            return image_format_assign_template2.format(
324                actual_angle_format=actual_angle_format,
325                mtl_format=angle_to_mtl_map[actual_angle_format],
326                init_function=wrap_init_function(
327                    angle_format_utils.get_internal_format_initializer(
328                        gl_format, actual_angle_format)),
329                actual_angle_format_fallback=actual_angle_format_fallback,
330                mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
331                init_function_fallback=wrap_init_function(
332                    angle_format_utils.get_internal_format_initializer(
333                        gl_format, actual_angle_format_fallback)),
334                fallback_condition=fallback_condition)
335        else:
336            # return ordinary block:
337            return image_format_assign_template1.format(
338                actual_angle_format=actual_angle_format,
339                mtl_format=angle_to_mtl_map[actual_angle_format],
340                init_function=wrap_init_function(
341                    angle_format_utils.get_internal_format_initializer(
342                        gl_format, actual_angle_format)))
343
344    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
345                                     gen_format_assign_code)
346
347
348# Generate format conversion switch case (ES 3.0 case)
349def gen_image_map_switch_es3_case(angle_format, actual_angle_format_info, angle_to_gl,
350                                  angle_to_mtl_map, mac_fallbacks):
351    gl_format = angle_to_gl[angle_format]
352
353    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
354        actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
355        return image_format_assign_template2.format(
356            actual_angle_format=actual_angle_format,
357            mtl_format=angle_to_mtl_map[actual_angle_format],
358            init_function=wrap_init_function(
359                angle_format_utils.get_internal_format_initializer(gl_format,
360                                                                   actual_angle_format)),
361            actual_angle_format_fallback=actual_angle_format_fallback,
362            mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
363            init_function_fallback=wrap_init_function(
364                angle_format_utils.get_internal_format_initializer(gl_format,
365                                                                   actual_angle_format_fallback)),
366            fallback_condition="display->supportsAppleGPUFamily(1)")
367
368    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
369                                     gen_format_assign_code)
370
371
372# Generate format conversion switch case (ASTC LDR/HDR case)
373def gen_image_map_switch_astc_case_iosmac(angle_format, angle_to_gl, angle_to_mtl_map):
374    gl_format = angle_to_gl[angle_format]
375
376    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
377        return image_format_assign_template2.format(
378            actual_angle_format=actual_angle_format,
379            mtl_format=angle_to_mtl_map[actual_angle_format] + "HDR",
380            init_function=wrap_init_function(
381                angle_format_utils.get_internal_format_initializer(gl_format,
382                                                                   actual_angle_format)),
383            actual_angle_format_fallback=actual_angle_format,
384            mtl_format_fallback=angle_to_mtl_map[actual_angle_format] + "LDR",
385            init_function_fallback=wrap_init_function(
386                angle_format_utils.get_internal_format_initializer(gl_format,
387                                                                   actual_angle_format)),
388            fallback_condition="display->supportsAppleGPUFamily(6)")
389
390    return gen_image_map_switch_case(angle_format, angle_format, angle_to_mtl_map,
391                                     gen_format_assign_code)
392
393
394def gen_image_map_switch_astc_case_tv_watchos(angle_format, angle_to_gl, angle_to_mtl_map):
395    gl_format = angle_to_gl[angle_format]
396
397    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
398        return image_format_assign_template1.format(
399            actual_angle_format=actual_angle_format,
400            mtl_format=angle_to_mtl_map[actual_angle_format] + "LDR",
401            init_function=wrap_init_function(
402                angle_format_utils.get_internal_format_initializer(gl_format,
403                                                                   actual_angle_format)))
404
405    return gen_image_map_switch_case(angle_format, angle_format, angle_to_mtl_map,
406                                     gen_format_assign_code)
407
408
409def gen_image_map_switch_string(image_table, angle_to_gl):
410    angle_override = image_table["override"]
411    mac_override = image_table["override_mac"]
412    mac_override_es3 = image_table["override_mac_es3"]
413    override_bc1 = image_table["override_bc1"]
414    ios_override = image_table["override_ios"]
415    mac_depth_fallbacks = image_table["depth_fallbacks_mac"]
416    angle_to_mtl = image_table["map"]
417    mac_specific_map = image_table["map_mac"].copy()
418    bc = image_table["map_bc"]
419    ios_specific_map = image_table["map_ios"]
420    astc_tpl_map = image_table["map_astc_tpl"]
421    sim_specific_map = image_table["map_sim"]
422    sim_override = image_table["override_sim"]
423
424    # mac_specific_map + angle_to_mtl:
425    mac_specific_map.update(bc)
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(override_bc1.keys()):
455        switch_data += gen_image_map_switch_simple_case(angle_format, override_bc1[angle_format],
456                                                        angle_to_gl, mac_angle_to_mtl)
457    switch_data += "#endif\n"
458
459    # Override missing ES 3.0 formats for older macOS SDK or Catalyst
460    switch_data += "#if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED < 110000)) || \\\n"
461    switch_data += "TARGET_OS_MACCATALYST\n"
462    for angle_format in sorted(mac_override_es3.keys()):
463        switch_data += gen_image_map_switch_simple_case(angle_format,
464                                                        mac_override_es3[angle_format],
465                                                        angle_to_gl, mac_angle_to_mtl)
466    switch_data += "#endif\n"
467
468    switch_data += "#if TARGET_OS_SIMULATOR\n"
469    for angle_format in sorted(sim_specific_map.keys()):
470        switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, angle_to_gl,
471                                                        sim_specific_map)
472    for angle_format in sorted(sim_override.keys()):
473        switch_data += gen_image_map_switch_simple_case(angle_format, sim_override[angle_format],
474                                                        angle_to_gl, sim_angle_to_mtl)
475    switch_data += "#if TARGET_OS_IOS || TARGET_OS_VISION\n"
476    for angle_format in sorted(astc_tpl_map.keys()):
477        switch_data += gen_image_map_switch_astc_case_iosmac(angle_format, angle_to_gl,
478                                                             astc_tpl_map)
479    switch_data += "#elif TARGET_OS_TV ||TARGET_OS_WATCH\n"
480
481    for angle_format in sorted(astc_tpl_map.keys()):
482        switch_data += gen_image_map_switch_astc_case_tv_watchos(angle_format, angle_to_gl,
483                                                                 astc_tpl_map)
484    switch_data += "#endif // ASTC formats\n"
485
486    # BC formats
487    switch_data += "#if (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) || \\\n"
488    switch_data += "    (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160400) || TARGET_OS_VISION\n"
489    for angle_format in sorted(bc.keys()):
490        switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, angle_to_gl,
491                                                        bc)
492    for angle_format in sorted(override_bc1.keys()):
493        switch_data += gen_image_map_switch_simple_case(angle_format, override_bc1[angle_format],
494                                                        angle_to_gl, bc)
495    switch_data += "#endif // BC formats on iOS/tvOS/visionOS \n"
496
497    # iOS specific
498    switch_data += "#elif TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST\n"
499    for angle_format in sorted(ios_specific_map.keys()):
500        switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, angle_to_gl,
501                                                        ios_specific_map)
502    for angle_format in sorted(ios_override.keys()):
503        switch_data += gen_image_map_switch_simple_case(angle_format, ios_override[angle_format],
504                                                        angle_to_gl, ios_angle_to_mtl)
505    switch_data += "#if TARGET_OS_IOS || TARGET_OS_VISION\n"
506    for angle_format in sorted(astc_tpl_map.keys()):
507        switch_data += gen_image_map_switch_astc_case_iosmac(angle_format, angle_to_gl,
508                                                             astc_tpl_map)
509
510    switch_data += "#elif TARGET_OS_TV ||TARGET_OS_WATCH\n"
511
512    for angle_format in sorted(astc_tpl_map.keys()):
513        switch_data += gen_image_map_switch_astc_case_tv_watchos(angle_format, angle_to_gl,
514                                                                 astc_tpl_map)
515    switch_data += "#endif // ASTC formats\n"
516
517    # BC formats
518    switch_data += "#if (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) || \\\n"
519    switch_data += "    (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160400) || TARGET_OS_VISION\n"
520    for angle_format in sorted(bc.keys()):
521        switch_data += gen_image_map_switch_simple_case(angle_format, angle_format, angle_to_gl,
522                                                        bc)
523    for angle_format in sorted(override_bc1.keys()):
524        switch_data += gen_image_map_switch_simple_case(angle_format, override_bc1[angle_format],
525                                                        angle_to_gl, bc)
526    switch_data += "#endif // BC formats on iOS/tvOS/visionOS \n"
527
528    switch_data += "#endif // TARGET_OS_IPHONE\n"
529
530    # Try to support all iOS formats on newer macOS with Apple GPU.
531    switch_data += "#if (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))\n"
532    for angle_format in sorted(ios_specific_map.keys()):
533        # Do not re-emit depth-specific formats.
534        if (angle_format not in mac_depth_fallbacks.keys()):
535            if (angle_format in mac_override_es3.keys()):
536                # ETC/EAC or packed 16-bit
537                switch_data += gen_image_map_switch_es3_case(angle_format, angle_format,
538                                                             angle_to_gl, ios_angle_to_mtl,
539                                                             mac_override_es3)
540            else:
541                # ASTC sRGB or PVRTC1
542                switch_data += gen_image_map_switch_simple_case(angle_format, angle_format,
543                                                                angle_to_gl, ios_specific_map)
544    # ASTC LDR or HDR
545    for angle_format in sorted(astc_tpl_map.keys()):
546        switch_data += gen_image_map_switch_astc_case_iosmac(angle_format, angle_to_gl,
547                                                             astc_tpl_map)
548    switch_data += "#endif // TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000)) \n"
549
550    switch_data += "        default:\n"
551    switch_data += "            this->metalFormat = MTLPixelFormatInvalid;\n"
552    switch_data += "            this->actualFormatId = angle::FormatID::NONE;"
553    return switch_data
554
555
556def gen_image_mtl_to_angle_switch_string(image_table):
557    angle_to_mtl = image_table["map"]
558    bc_map = image_table["map_bc"]
559    mac_specific_map = image_table["map_mac"]
560    ios_specific_map = image_table["map_ios"]
561    astc_tpl_map = image_table["map_astc_tpl"]
562
563    switch_data = ''
564
565    # Common case
566    for angle_format in sorted(angle_to_mtl.keys()):
567        switch_data += case_image_mtl_to_angle_template.format(
568            mtl_format=angle_to_mtl[angle_format], angle_format=angle_format)
569
570    # BC formats
571    switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST ||\\\n"
572    switch_data += "    (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) ||\\\n"
573    switch_data += "    (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160400) || TARGET_OS_VISION\n"
574    for angle_format in sorted(bc_map.keys()):
575        switch_data += case_image_mtl_to_angle_template.format(
576            mtl_format=bc_map[angle_format], angle_format=angle_format)
577    switch_data += "#endif  // BC formats\n"
578
579    # Mac specific
580    switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
581    for angle_format in sorted(mac_specific_map.keys()):
582        switch_data += case_image_mtl_to_angle_template.format(
583            mtl_format=mac_specific_map[angle_format], angle_format=angle_format)
584    switch_data += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
585
586    # iOS + macOS 11.0+ specific
587    switch_data += "#if TARGET_OS_IPHONE || (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))\n"
588    for angle_format in sorted(ios_specific_map.keys()):
589        # ETC1_R8G8B8_UNORM_BLOCK is a duplicated of ETC2_R8G8B8_UNORM_BLOCK
590        if angle_format == 'ETC1_R8G8B8_UNORM_BLOCK':
591            continue
592        # Do not re-emit formats that are in the general Mac table
593        if angle_format in mac_specific_map.keys():
594            continue
595        switch_data += case_image_mtl_to_angle_template.format(
596            mtl_format=ios_specific_map[angle_format], angle_format=angle_format)
597    for angle_format in sorted(astc_tpl_map.keys()):
598        switch_data += case_image_mtl_to_angle_template.format(
599            mtl_format=astc_tpl_map[angle_format] + "LDR", angle_format=angle_format)
600    switch_data += "#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION\n"
601    for angle_format in sorted(astc_tpl_map.keys()):
602        switch_data += case_image_mtl_to_angle_template.format(
603            mtl_format=astc_tpl_map[angle_format] + "HDR", angle_format=angle_format)
604    switch_data += "#endif // TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION\n"
605    switch_data += "#endif  // TARGET_OS_IPHONE || mac 11.0+\n"
606
607    switch_data += "        default:\n"
608    switch_data += "            return angle::FormatID::NONE;\n"
609    return switch_data
610
611
612def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map):
613    mtl_format = angle_to_mtl_map[actual_angle_fmt]
614    copy_function, default_alpha, same_gl_type = get_vertex_copy_function_and_default_alpha(
615        angle_fmt, actual_angle_fmt)
616
617    if actual_angle_fmt in override_packed_map:
618        # This format has an override when used in tightly packed buffer,
619        # Return if else block
620        angle_fmt_packed = override_packed_map[actual_angle_fmt]
621        mtl_format_packed = angle_to_mtl_map[angle_fmt_packed]
622        copy_function_packed, default_alpha_packed, same_gl_type_packed = get_vertex_copy_function_and_default_alpha(
623            angle_fmt, angle_fmt_packed)
624
625        return case_vertex_format_template2.format(
626            angle_format=angle_fmt,
627            mtl_format_packed=mtl_format_packed,
628            actual_angle_format_packed=angle_fmt_packed,
629            vertex_copy_function_packed=copy_function_packed,
630            default_alpha_packed=default_alpha_packed,
631            same_gl_type_packed=wrap_actual_same_gl_type(same_gl_type_packed),
632            mtl_format=mtl_format,
633            actual_angle_format=actual_angle_fmt,
634            vertex_copy_function=copy_function,
635            default_alpha=default_alpha,
636            same_gl_type=wrap_actual_same_gl_type(same_gl_type))
637    else:
638        # This format has no packed buffer's override, return ordinary block.
639        return case_vertex_format_template1.format(
640            angle_format=angle_fmt,
641            mtl_format=mtl_format,
642            actual_angle_format=actual_angle_fmt,
643            vertex_copy_function=copy_function,
644            default_alpha=default_alpha,
645            same_gl_type=wrap_actual_same_gl_type(same_gl_type))
646
647
648def gen_vertex_map_switch_string(vertex_table):
649    angle_to_mtl = vertex_table["map"]
650    angle_override = vertex_table["override"]
651    override_packed = vertex_table["override_tightly_packed"]
652
653    switch_data = ''
654    for angle_fmt in sorted(angle_to_mtl.keys()):
655        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_fmt, angle_to_mtl,
656                                                  override_packed)
657
658    for angle_fmt in sorted(angle_override.keys()):
659        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_override[angle_fmt],
660                                                  angle_to_mtl, override_packed)
661
662    switch_data += "        default:\n"
663    switch_data += "            this->metalFormat = MTLVertexFormatInvalid;\n"
664    switch_data += "            this->actualFormatId = angle::FormatID::NONE;\n"
665    switch_data += "            this->vertexLoadFunction = nullptr;"
666    switch_data += "            this->defaultAlpha = 0;"
667    switch_data += "            this->actualSameGLType = false;"
668    return switch_data
669
670
671def gen_mtl_format_caps_init_string(map_image):
672    caps = map_image['caps']
673    bc_caps = map_image['caps_bc']
674    mac_caps = map_image['caps_mac']
675    ios_platform_caps = map_image['caps_ios_platform']
676    ios_specific_caps = map_image['caps_ios_specific']
677    caps_init_str = ''
678
679    def cap_to_param(caps, key):
680        return '/** ' + key + '*/ ' + caps.get(key, 'false')
681
682    def caps_to_cpp(caps_table):
683        init_str = ''
684        for mtl_format in sorted(caps_table.keys()):
685            caps = caps_table[mtl_format]
686            filterable = cap_to_param(caps, 'filterable')
687            writable = cap_to_param(caps, 'writable')
688            colorRenderable = cap_to_param(caps, 'colorRenderable')
689            depthRenderable = cap_to_param(caps, 'depthRenderable')
690            blendable = cap_to_param(caps, 'blendable')
691            multisample = cap_to_param(caps, 'multisample')
692            resolve = cap_to_param(caps, 'resolve')
693
694            init_str += "    setFormatCaps({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7});\n\n".format(
695                mtl_format, filterable, writable, blendable, multisample, resolve, colorRenderable,
696                depthRenderable)
697
698        return init_str
699
700    caps_init_str += caps_to_cpp(caps)
701
702    caps_init_str += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST ||\\\n"
703    caps_init_str += "    (TARGET_OS_IOS && __IPHONE_OS_VERSION_MAX_ALLOWED >= 160400) ||\\\n"
704    caps_init_str += "    (TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160400) || TARGET_OS_VISION\n"
705    caps_init_str += caps_to_cpp(bc_caps)
706    caps_init_str += "#endif  // BC formats\n"
707
708    caps_init_str += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
709    caps_init_str += caps_to_cpp(mac_caps)
710    caps_init_str += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
711
712    caps_init_str += "#if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST) || \\\n"
713    caps_init_str += "    (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))\n"
714
715    caps_init_str += caps_to_cpp(ios_platform_caps)
716
717    caps_init_str += "#if TARGET_OS_IOS || TARGET_OS_OSX || TARGET_OS_VISION\n"
718    caps_init_str += caps_to_cpp(ios_specific_caps)
719    caps_init_str += "#endif // TARGET_OS_IOS || mac 11.0+ || TARGET_OS_VISION\n"
720    caps_init_str += "#endif // TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST || mac 11.0+ \n"
721
722    return caps_init_str
723
724
725def main():
726    data_source_name = 'mtl_format_map.json'
727    # auto_script parameters.
728    if len(sys.argv) > 1:
729        inputs = ['../angle_format.py', '../angle_format_map.json', data_source_name]
730        outputs = ['mtl_format_table_autogen.mm']
731
732        if sys.argv[1] == 'inputs':
733            print(','.join(inputs))
734        elif sys.argv[1] == 'outputs':
735            print(','.join(outputs))
736        else:
737            print('Invalid script parameters')
738            return 1
739        return 0
740
741    angle_to_gl = angle_format_utils.load_inverse_table('../angle_format_map.json')
742
743    map_json = angle_format_utils.load_json(data_source_name)
744    map_image = map_json["image"]
745    map_vertex = map_json["vertex"]
746
747    image_switch_data = gen_image_map_switch_string(map_image, angle_to_gl)
748    image_mtl_to_angle_switch_data = gen_image_mtl_to_angle_switch_string(map_image)
749
750    vertex_switch_data = gen_vertex_map_switch_string(map_vertex)
751
752    caps_init_str = gen_mtl_format_caps_init_string(map_image)
753
754    output_cpp = template_autogen_inl.format(
755        script_name=os.path.basename(sys.argv[0]),
756        data_source_name=data_source_name,
757        angle_image_format_switch=image_switch_data,
758        mtl_pixel_format_switch=image_mtl_to_angle_switch_data,
759        angle_vertex_format_switch=vertex_switch_data,
760        metal_format_caps=caps_init_str)
761    with open('mtl_format_table_autogen.mm', 'wt') as out_file:
762        out_file.write(output_cpp)
763        out_file.close()
764
765
766if __name__ == '__main__':
767    sys.exit(main())
768