• 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 pprint
20import re
21import sys
22
23sys.path.append('..')
24import angle_format as angle_format_utils
25
26template_autogen_inl = """// GENERATED FILE - DO NOT EDIT.
27// Generated by {script_name} using data from {data_source_name}
28//
29// Copyright 2020 The ANGLE Project Authors. All rights reserved.
30// Use of this source code is governed by a BSD-style license that can be
31// found in the LICENSE file.
32//
33// Metal Format table:
34//   Conversion from ANGLE format to Metal format.
35
36#import <Metal/Metal.h>
37#include <TargetConditionals.h>
38
39#include "image_util/copyimage.h"
40#include "image_util/generatemip.h"
41#include "image_util/loadimage.h"
42#include "libANGLE/renderer/Format.h"
43#include "libANGLE/renderer/metal/DisplayMtl.h"
44#include "libANGLE/renderer/metal/mtl_format_utils.h"
45#include "libANGLE/renderer/metal/mtl_utils.h"
46
47using namespace angle;
48
49namespace rx
50{{
51namespace mtl
52{{
53
54angle::FormatID Format::MetalToAngleFormatID(MTLPixelFormat formatMtl)
55{{
56    // Actual conversion
57    switch (formatMtl)
58    {{
59{mtl_pixel_format_switch}
60    }}
61}}
62
63void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
64{{
65    this->intendedFormatId = intendedFormatId_;
66#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
67    id<MTLDevice> metalDevice = display->getMetalDevice();
68#endif
69
70    // Actual conversion
71    switch (this->intendedFormatId)
72    {{
73{angle_image_format_switch}
74    }}
75}}
76
77void VertexFormat::init(angle::FormatID angleFormatId, bool tightlyPacked)
78{{
79    this->intendedFormatId = angleFormatId;
80
81    // Actual conversion
82    switch (this->intendedFormatId)
83    {{
84{angle_vertex_format_switch}
85    }}
86}}
87
88void FormatTable::initNativeFormatCapsAutogen(const DisplayMtl *display)
89{{
90    const angle::FeaturesMtl &featuresMtl = display->getFeatures();
91    // Skip auto resolve if either hasDepth/StencilAutoResolve or allowMultisampleStoreAndResolve
92    // feature are disabled.
93    bool supportDepthAutoResolve = featuresMtl.hasDepthAutoResolve.enabled &&
94                                   featuresMtl.allowMultisampleStoreAndResolve.enabled;
95    bool supportStencilAutoResolve = featuresMtl.hasStencilAutoResolve.enabled &&
96                                     featuresMtl.allowMultisampleStoreAndResolve.enabled;
97    bool supportDepthStencilAutoResolve = supportDepthAutoResolve && supportStencilAutoResolve;
98
99    // Source: https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
100    {metal_format_caps}
101}}
102
103}}  // namespace mtl
104}}  // namespace rx
105"""
106
107image_format_assign_template1 = """
108            this->metalFormat = {mtl_format};
109            this->actualFormatId = angle::FormatID::{actual_angle_format};{init_function}"""
110
111image_format_assign_template2 = """
112            if ({fallback_condition})
113            {{
114                this->metalFormat = {mtl_format};
115                this->actualFormatId = angle::FormatID::{actual_angle_format};{init_function}
116            }}
117            else
118            {{
119                this->metalFormat = {mtl_format_fallback};
120                this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};{init_function_fallback}
121            }}"""
122
123#D16 is fully supported on  Apple3+. However, on
124#previous  versions of Apple hardware, some operations can cause
125#undefined behavior.
126image_format_assign_template3 = """
127            if (mtl::SupportsIOSGPUFamily(metalDevice, 3))
128            {{
129                this->metalFormat = {mtl_format};
130                this->actualFormatId = angle::FormatID::{actual_angle_format};{init_function}
131            }}
132            else
133            {{
134                this->metalFormat = {mtl_format_fallback};
135                this->actualFormatId = angle::FormatID::{actual_angle_format_fallback};{init_function_fallback}
136            }}"""
137
138case_image_format_template1 = """        case angle::FormatID::{angle_format}:
139            {image_format_assign}
140            break;
141
142"""
143
144case_image_format_template2 = """        case angle::FormatID::{angle_format}:
145#if defined(__IPHONE_13_0) || defined(__MAC_10_15)
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#endif  // #if defined(__IPHONE_13_0) || defined(__MAC_10_15)
154            {{
155                {image_format_assign_default}
156            }}
157            break;
158
159"""
160
161case_image_mtl_to_angle_template = """        case {mtl_format}:
162            return angle::FormatID::{angle_format};
163"""
164
165case_vertex_format_template1 = """        case angle::FormatID::{angle_format}:
166            this->metalFormat = {mtl_format};
167            this->actualFormatId = angle::FormatID::{actual_angle_format};
168            this->vertexLoadFunction = {vertex_copy_function};
169            this->defaultAlpha = {default_alpha};{same_gl_type}
170            break;
171
172"""
173
174case_vertex_format_template2 = """        case angle::FormatID::{angle_format}:
175            if (tightlyPacked)
176            {{
177                this->metalFormat = {mtl_format_packed};
178                this->actualFormatId = angle::FormatID::{actual_angle_format_packed};
179                this->vertexLoadFunction = {vertex_copy_function_packed};
180                this->defaultAlpha = {default_alpha_packed};{same_gl_type_packed}
181            }}
182            else
183            {{
184                this->metalFormat = {mtl_format};
185                this->actualFormatId = angle::FormatID::{actual_angle_format};
186                this->vertexLoadFunction = {vertex_copy_function};
187                this->defaultAlpha = {default_alpha};{same_gl_type}
188            }}
189            break;
190
191"""
192
193
194def wrap_init_function(str):
195    return '' if str == 'nullptr' else f'this->initFunction = {str};'
196
197
198def wrap_actual_same_gl_type(str):
199    return '' if str == 'true' else f'this->actualSameGLType = {str};'
200
201
202# NOTE(hqle): This is a modified version of the get_vertex_copy_function() function in
203# src/libANGLE/renderer/angle_format.py
204# - Return value is a tuple {copy_function, default_alpha_value, have_same_gl_type}.
205def get_vertex_copy_function_and_default_alpha(src_format, dst_format):
206    if dst_format == "NONE":
207        return "nullptr", 0, "false"
208
209    num_channel = len(angle_format_utils.get_channel_tokens(src_format))
210    if num_channel < 1 or num_channel > 4:
211        return "nullptr", 0, "false"
212
213    src_gl_type = angle_format_utils.get_format_gl_type(src_format)
214    dst_gl_type = angle_format_utils.get_format_gl_type(dst_format)
215
216    if src_gl_type == dst_gl_type:
217        if src_format.startswith('R10G10B10A2'):
218            return 'CopyNativeVertexData<GLuint, 1, 1, 0>', 0, "true"
219
220        if src_gl_type == None:
221            return 'nullptr', 0, "true"
222        dst_num_channel = len(angle_format_utils.get_channel_tokens(dst_format))
223        default_alpha = '1'
224
225        if num_channel == dst_num_channel or dst_num_channel < 4:
226            default_alpha = '0'
227        elif 'A16_FLOAT' in dst_format:
228            default_alpha = 'gl::Float16One'
229        elif 'A32_FLOAT' in dst_format:
230            default_alpha = 'gl::Float32One'
231        elif 'NORM' in dst_format:
232            default_alpha = 'std::numeric_limits<%s>::max()' % (src_gl_type)
233
234        return 'CopyNativeVertexData<%s, %d, %d, %s>' % (src_gl_type, num_channel, dst_num_channel,
235                                                         default_alpha), default_alpha, "true"
236
237    if src_format.startswith('R10G10B10A2'):
238        assert 'FLOAT' in dst_format, ('get_vertex_copy_function: can only convert to float,' +
239                                       ' not to ' + dst_format)
240        is_signed = 'true' if 'SINT' in src_format or 'SNORM' in src_format or 'SSCALED' in src_format else 'false'
241        is_normal = 'true' if 'NORM' in src_format else 'false'
242        return 'CopyXYZ10W2ToXYZWFloatVertexData<%s, %s, true, false>' % (is_signed,
243                                                                          is_normal), 0, "false"
244
245    return angle_format_utils.get_vertex_copy_function(src_format, dst_format), 0, "false"
246
247
248# Generate format conversion switch case (generic case)
249
250
251def gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
252                              assign_gen_func):
253    if isinstance(actual_angle_format_info, dict):
254        default_actual_angle_format = actual_angle_format_info['default']
255        # Check if the format can be override with swizzle feature
256        if 'swizzle' in actual_angle_format_info:
257            swizzle_info = actual_angle_format_info['swizzle']
258            swizzle_channels = swizzle_info[0]
259            swizzled_actual_angle_format = swizzle_info[1]
260            swizzle_map = {
261                'R': 'GL_RED',
262                'G': 'GL_GREEN',
263                'B': 'GL_BLUE',
264                'A': 'GL_ALPHA',
265                '1': 'GL_ONE',
266                '0': 'GL_ZERO',
267            }
268
269            mtl_swizzle_make = '{{{r}, {g}, {b}, {a}}}'.format(
270                r=swizzle_map[swizzle_channels[0:1]],
271                g=swizzle_map[swizzle_channels[1:2]],
272                b=swizzle_map[swizzle_channels[2:3]],
273                a=swizzle_map[swizzle_channels[3:]])
274            return case_image_format_template2.format(
275                angle_format=angle_format,
276                image_format_assign_default=assign_gen_func(default_actual_angle_format,
277                                                            angle_to_mtl_map),
278                image_format_assign_swizzled=assign_gen_func(swizzled_actual_angle_format,
279                                                             angle_to_mtl_map),
280                mtl_swizzle=mtl_swizzle_make)
281        else:
282            # Only default case
283            return gen_image_map_switch_case(angle_format, default_actual_angle_format,
284                                             angle_to_mtl_map, assign_gen_func)
285    else:
286        # Default case
287        return case_image_format_template1.format(
288            angle_format=angle_format,
289            image_format_assign=assign_gen_func(actual_angle_format_info, angle_to_mtl_map))
290
291
292# Generate format conversion switch case (simple case)
293
294
295def gen_image_map_switch_simple_case(angle_format, actual_angle_format_info, angle_to_gl,
296                                     angle_to_mtl_map):
297
298    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
299        return image_format_assign_template1.format(
300            actual_angle_format=actual_angle_format,
301            mtl_format=angle_to_mtl_map[actual_angle_format],
302            init_function=wrap_init_function(
303                angle_format_utils.get_internal_format_initializer(angle_to_gl[angle_format],
304                                                                   actual_angle_format)))
305
306    return gen_image_map_switch_case(angle_format, actual_angle_format_info, angle_to_mtl_map,
307                                     gen_format_assign_code)
308
309
310# Generate format conversion switch case (Mac case)
311
312
313def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_to_gl,
314                                  angle_to_mtl_map, mac_fallbacks):
315    gl_format = angle_to_gl[angle_format]
316
317    def gen_format_assign_code(actual_angle_format, angle_to_mtl_map):
318        if actual_angle_format in mac_fallbacks:
319            # This format requires fallback when depth24Stencil8PixelFormatSupported flag is false.
320            # Fallback format:
321            actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
322            fallback_condition = "metalDevice.depth24Stencil8PixelFormatSupported && \
323                                 !display->getFeatures().forceD24S8AsUnsupported.enabled"
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_d24s8_fallbacks = image_table["d24s8_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_d24s8_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        if (angle_format in mac_override_es3.keys()):
511            # ETC/EAC or packed 16-bit
512            switch_data += gen_image_map_switch_es3_case(angle_format, angle_format, angle_to_gl,
513                                                         ios_angle_to_mtl, mac_override_es3)
514        else:
515            # ASTC sRGB or PVRTC1
516            switch_data += gen_image_map_switch_simple_case(angle_format, angle_format,
517                                                            angle_to_gl, ios_specific_map)
518    # ASTC LDR or HDR
519    for angle_format in sorted(astc_tpl_map.keys()):
520        switch_data += gen_image_map_switch_astc_case_iosmac(angle_format, angle_to_gl,
521                                                             astc_tpl_map)
522    switch_data += "#endif // TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000)) \n"
523
524    switch_data += "        default:\n"
525    switch_data += "            this->metalFormat = MTLPixelFormatInvalid;\n"
526    switch_data += "            this->actualFormatId = angle::FormatID::NONE;"
527    return switch_data
528
529
530def gen_image_mtl_to_angle_switch_string(image_table):
531    angle_to_mtl = image_table["map"]
532    mac_specific_map = image_table["map_mac"]
533    ios_specific_map = image_table["map_ios"]
534    astc_tpl_map = image_table["map_astc_tpl"]
535
536    switch_data = ''
537
538    # Common case
539    for angle_format in sorted(angle_to_mtl.keys()):
540        switch_data += case_image_mtl_to_angle_template.format(
541            mtl_format=angle_to_mtl[angle_format], angle_format=angle_format)
542
543    # Mac specific
544    switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
545    for angle_format in sorted(mac_specific_map.keys()):
546        switch_data += case_image_mtl_to_angle_template.format(
547            mtl_format=mac_specific_map[angle_format], angle_format=angle_format)
548    switch_data += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
549
550    # iOS + macOS 11.0+ specific
551    switch_data += "#if TARGET_OS_IPHONE || (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))\n"
552    for angle_format in sorted(ios_specific_map.keys()):
553        # ETC1_R8G8B8_UNORM_BLOCK is a duplicated of ETC2_R8G8B8_UNORM_BLOCK
554        if angle_format == 'ETC1_R8G8B8_UNORM_BLOCK':
555            continue
556        switch_data += case_image_mtl_to_angle_template.format(
557            mtl_format=ios_specific_map[angle_format], angle_format=angle_format)
558    for angle_format in sorted(astc_tpl_map.keys()):
559        switch_data += case_image_mtl_to_angle_template.format(
560            mtl_format=astc_tpl_map[angle_format] + "LDR", angle_format=angle_format)
561    switch_data += "#if TARGET_OS_IOS || TARGET_OS_OSX \n"
562    for angle_format in sorted(astc_tpl_map.keys()):
563        switch_data += case_image_mtl_to_angle_template.format(
564            mtl_format=astc_tpl_map[angle_format] + "HDR", angle_format=angle_format)
565    switch_data += "#endif // TARGET_OS_IOS || TARGET_OS_OSX\n"
566    switch_data += "#endif  // TARGET_OS_IPHONE || mac 11.0+\n"
567
568    switch_data += "        default:\n"
569    switch_data += "            return angle::FormatID::NONE;\n"
570    return switch_data
571
572
573def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map):
574    mtl_format = angle_to_mtl_map[actual_angle_fmt]
575    copy_function, default_alpha, same_gl_type = get_vertex_copy_function_and_default_alpha(
576        angle_fmt, actual_angle_fmt)
577
578    if actual_angle_fmt in override_packed_map:
579        # This format has an override when used in tightly packed buffer,
580        # Return if else block
581        angle_fmt_packed = override_packed_map[actual_angle_fmt]
582        mtl_format_packed = angle_to_mtl_map[angle_fmt_packed]
583        copy_function_packed, default_alpha_packed, same_gl_type_packed = get_vertex_copy_function_and_default_alpha(
584            angle_fmt, angle_fmt_packed)
585
586        return case_vertex_format_template2.format(
587            angle_format=angle_fmt,
588            mtl_format_packed=mtl_format_packed,
589            actual_angle_format_packed=angle_fmt_packed,
590            vertex_copy_function_packed=copy_function_packed,
591            default_alpha_packed=default_alpha_packed,
592            same_gl_type_packed=wrap_actual_same_gl_type(same_gl_type_packed),
593            mtl_format=mtl_format,
594            actual_angle_format=actual_angle_fmt,
595            vertex_copy_function=copy_function,
596            default_alpha=default_alpha,
597            same_gl_type=wrap_actual_same_gl_type(same_gl_type))
598    else:
599        # This format has no packed buffer's override, return ordinary block.
600        return case_vertex_format_template1.format(
601            angle_format=angle_fmt,
602            mtl_format=mtl_format,
603            actual_angle_format=actual_angle_fmt,
604            vertex_copy_function=copy_function,
605            default_alpha=default_alpha,
606            same_gl_type=wrap_actual_same_gl_type(same_gl_type))
607
608
609def gen_vertex_map_switch_string(vertex_table):
610    angle_to_mtl = vertex_table["map"]
611    angle_override = vertex_table["override"]
612    override_packed = vertex_table["override_tightly_packed"]
613
614    switch_data = ''
615    for angle_fmt in sorted(angle_to_mtl.keys()):
616        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_fmt, angle_to_mtl,
617                                                  override_packed)
618
619    for angle_fmt in sorted(angle_override.keys()):
620        switch_data += gen_vertex_map_switch_case(angle_fmt, angle_override[angle_fmt],
621                                                  angle_to_mtl, override_packed)
622
623    switch_data += "        default:\n"
624    switch_data += "            this->metalFormat = MTLVertexFormatInvalid;\n"
625    switch_data += "            this->actualFormatId = angle::FormatID::NONE;\n"
626    switch_data += "            this->vertexLoadFunction = nullptr;"
627    switch_data += "            this->defaultAlpha = 0;"
628    switch_data += "            this->actualSameGLType = false;"
629    return switch_data
630
631
632def gen_mtl_format_caps_init_string(map_image):
633    caps = map_image['caps']
634    mac_caps = map_image['caps_mac']
635    ios_platform_caps = map_image['caps_ios_platform']
636    ios_specific_caps = map_image['caps_ios_specific']
637    caps_init_str = ''
638
639    def cap_to_param(caps, key):
640        return '/** ' + key + '*/ ' + caps.get(key, 'false')
641
642    def caps_to_cpp(caps_table):
643        init_str = ''
644        for mtl_format in sorted(caps_table.keys()):
645            caps = caps_table[mtl_format]
646            filterable = cap_to_param(caps, 'filterable')
647            writable = cap_to_param(caps, 'writable')
648            colorRenderable = cap_to_param(caps, 'colorRenderable')
649            depthRenderable = cap_to_param(caps, 'depthRenderable')
650            blendable = cap_to_param(caps, 'blendable')
651            multisample = cap_to_param(caps, 'multisample')
652            resolve = cap_to_param(caps, 'resolve')
653
654            init_str += "    setFormatCaps({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7});\n\n".format(
655                mtl_format, filterable, writable, blendable, multisample, resolve, colorRenderable,
656                depthRenderable)
657
658        return init_str
659
660    caps_init_str += caps_to_cpp(caps)
661
662    caps_init_str += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
663    caps_init_str += caps_to_cpp(mac_caps)
664    caps_init_str += "#endif  // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
665
666    caps_init_str += "#if (TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST) || \\\n"
667    caps_init_str += "    (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))\n"
668
669    caps_init_str += caps_to_cpp(ios_platform_caps)
670
671    caps_init_str += "#if TARGET_OS_IOS || TARGET_OS_OSX\n"
672    caps_init_str += caps_to_cpp(ios_specific_caps)
673    caps_init_str += "#endif // TARGET_OS_IOS || mac 11.0+ \n"
674    caps_init_str += "#endif // TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST || mac 11.0+ \n"
675
676    return caps_init_str
677
678
679def main():
680    data_source_name = 'mtl_format_map.json'
681    # auto_script parameters.
682    if len(sys.argv) > 1:
683        inputs = ['../angle_format.py', '../angle_format_map.json', data_source_name]
684        outputs = ['mtl_format_table_autogen.mm']
685
686        if sys.argv[1] == 'inputs':
687            print(','.join(inputs))
688        elif sys.argv[1] == 'outputs':
689            print(','.join(outputs))
690        else:
691            print('Invalid script parameters')
692            return 1
693        return 0
694
695    angle_to_gl = angle_format_utils.load_inverse_table('../angle_format_map.json')
696
697    map_json = angle_format_utils.load_json(data_source_name)
698    map_image = map_json["image"]
699    map_vertex = map_json["vertex"]
700
701    image_switch_data = gen_image_map_switch_string(map_image, angle_to_gl)
702    image_mtl_to_angle_switch_data = gen_image_mtl_to_angle_switch_string(map_image)
703
704    vertex_switch_data = gen_vertex_map_switch_string(map_vertex)
705
706    caps_init_str = gen_mtl_format_caps_init_string(map_image)
707
708    output_cpp = template_autogen_inl.format(
709        script_name=sys.argv[0],
710        data_source_name=data_source_name,
711        angle_image_format_switch=image_switch_data,
712        mtl_pixel_format_switch=image_mtl_to_angle_switch_data,
713        angle_vertex_format_switch=vertex_switch_data,
714        metal_format_caps=caps_init_str)
715    with open('mtl_format_table_autogen.mm', 'wt') as out_file:
716        out_file.write(output_cpp)
717        out_file.close()
718
719
720if __name__ == '__main__':
721    sys.exit(main())
722