import sys
import os
import registry_xml
template_gl_enums_header = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}.
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// gl_enum_utils_autogen.h:
// mapping of GLenum value to string.
# ifndef COMMON_GL_ENUM_UTILS_AUTOGEN_H_
# define COMMON_GL_ENUM_UTILS_AUTOGEN_H_
namespace gl
{{
enum class GLESEnum
{{
{gles_enum_groups}
}};
}} // namespace gl
# endif // COMMON_GL_ENUM_UTILS_AUTOGEN_H_
"""
template_gl_enums_source = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}.
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// gl_enum_utils_autogen.cpp:
// mapping of GLenum value to string.
#include "common/gl_enum_utils_autogen.h"
#include "common/debug.h"
#include "common/gl_enum_utils.h"
#include <algorithm>
#include <cstring>
namespace gl
{{
namespace
{{
const char *UnknownEnumToString(unsigned int value)
{{
constexpr size_t kBufferSize = 64;
static thread_local char sBuffer[kBufferSize];
snprintf(sBuffer, kBufferSize, "0x%04X", value);
return sBuffer;
}}
}} // anonymous namespace
const char *GLenumToString(GLESEnum enumGroup, unsigned int value)
{{
switch (enumGroup)
{{
{gles_enums_value_to_string_table}
default:
return UnknownEnumToString(value);
}}
}}
namespace
{{
using StringEnumEntry = std::pair<const char*, unsigned int>;
static StringEnumEntry g_stringEnumTable[] = {{
{string_to_enum_table}
}};
const size_t g_numStringEnums = std::size(g_stringEnumTable);
}} // anonymous namespace
unsigned int StringToGLenum(const char *str)
{{
auto it = std::lower_bound(
&g_stringEnumTable[0], &g_stringEnumTable[g_numStringEnums], str,
[](const StringEnumEntry& a, const char* b) {{ return strcmp(a.first, b) < 0; }});
if (strcmp(it->first, str) == 0)
{{
return it->second;
}}
UNREACHABLE();
return 0;
}}
}} // namespace gl
"""
template_enum_group_case = """case {api_enum}::{group_name}: {{
switch (value) {{
{inner_group_cases}
default:
return UnknownEnumToString(value);
}}
}}
"""
template_enum_value_to_string_case = """case {value}: return {name};"""
exclude_enum_groups = {'SpecialNumbers'}
empty_enum_groups = ['SemaphoreParameterName', 'ShaderBinaryFormat']
def dump_value_to_string_mapping(enum_groups, api_enum):
exporting_groups = list()
for group_name, inner_mapping in enum_groups.items():
string_value_pairs = list(
filter(lambda x: x[1] >= 0 and x[1] <= 0xFFFFFFFFF, inner_mapping.items()))
if not string_value_pairs:
continue
string_value_pairs.sort(key=lambda x: (x[1], len(x[0]), x[0]))
exporting_string_value_pairs = list()
for index, pair in enumerate(string_value_pairs):
if index == 0 or pair[1] != string_value_pairs[index - 1][1]:
exporting_string_value_pairs.append(pair)
inner_code_block = "\n".join([
template_enum_value_to_string_case.format(
value='0x%X' % value,
name='"%s"' % name,
) for name, value in exporting_string_value_pairs
])
exporting_groups.append((group_name, inner_code_block))
return "\n".join([
template_enum_group_case.format(
api_enum=api_enum,
group_name=group_name,
inner_group_cases=inner_code_block,
) for group_name, inner_code_block in sorted(exporting_groups, key=lambda x: x[0])
])
def dump_string_to_value_mapping(enums_and_values):
def f(value):
if value < 0:
return str(value)
if value < 0xFFFF:
return "0x%04X" % value
if value <= 0xFFFFFFFF:
return "0x%X" % value
else:
return "0xFFFFFFFF"
return '\n'.join('{"%s", %s},' % (k, f(v)) for k, v in sorted(enums_and_values))
def main(header_output_path, source_output_path):
xml = registry_xml.RegistryXML('gl.xml', 'gl_angle_ext.xml')
gles_enums = set()
for feature in xml.root.findall('feature'):
for require in feature.findall('require'):
assert 'api' not in require.attrib
if 'gles' in feature.attrib['api']:
for enum in require.findall('enum'):
gles_enums.add(enum.attrib['name'])
for extensions in xml.root.findall('extensions'):
for extension in extensions.findall('extension'):
if extension.attrib['name'] in registry_xml.supported_extensions:
for require in extension.findall('require'):
ext_apis = extension.attrib['supported'].split('|')
if ('api' not in require.attrib or 'gles' in require.attrib['api']) and (
'gles' in extension.attrib['supported']):
for enum in require.findall('enum'):
gles_enums.add(enum.attrib['name'])
gles_enum_groups = dict()
gles_default_enums = dict()
gles_enum_groups[registry_xml.default_enum_group_name] = gles_default_enums
enums_and_values = []
for enums_node in xml.root.findall('enums'):
for enum in enums_node.findall('enum'):
enum_name = enum.attrib['name']
enum_value = int(enum.attrib['value'], base=16)
enums_and_values.append((enum_name, enum_value))
if enum_name in gles_enums:
gles_default_enums[enum_name] = enum_value
if 'group' in enum.attrib:
for enum_group in enum.attrib['group'].split(','):
if enum_group in exclude_enum_groups:
continue
if enum_name in gles_enums:
if enum_group not in gles_enum_groups:
gles_enum_groups[enum_group] = dict()
gles_enum_groups[enum_group][enum_name] = enum_value
for empty_group in empty_enum_groups:
assert empty_group not in gles_enum_groups, 'Remove %s from the empty groups list, it has enums now.' % empty_group
if empty_group not in gles_enum_groups:
gles_enum_groups[empty_group] = dict()
header_content = template_gl_enums_header.format(
script_name=os.path.basename(sys.argv[0]),
data_source_name="gl.xml and gl_angle_ext.xml",
gles_enum_groups=',\n'.join(sorted(gles_enum_groups.keys())))
header_output_path = registry_xml.script_relative(header_output_path)
with open(header_output_path, 'w') as f:
f.write(header_content)
gles_enums_value_to_string_table = dump_value_to_string_mapping(gles_enum_groups, 'GLESEnum')
string_to_enum_table = dump_string_to_value_mapping(enums_and_values)
source_content = template_gl_enums_source.format(
script_name=os.path.basename(sys.argv[0]),
data_source_name="gl.xml and gl_angle_ext.xml",
gles_enums_value_to_string_table=gles_enums_value_to_string_table,
string_to_enum_table=string_to_enum_table,
)
source_output_path = registry_xml.script_relative(source_output_path)
with open(source_output_path, 'w') as f:
f.write(source_content)
return 0
if __name__ == '__main__':
inputs = [
'../third_party/OpenGL-Registry/src/xml/gl.xml',
'gl_angle_ext.xml',
'registry_xml.py',
]
gl_enum_utils_autogen_base_path = '../src/common/gl_enum_utils_autogen'
outputs = [
gl_enum_utils_autogen_base_path + '.h',
gl_enum_utils_autogen_base_path + '.cpp',
]
if len(sys.argv) > 1:
if sys.argv[1] == 'inputs':
print(','.join(inputs))
elif sys.argv[1] == 'outputs':
print(','.join(outputs))
else:
sys.exit(
main(
registry_xml.script_relative(outputs[0]),
registry_xml.script_relative(outputs[1])))