1#!/usr/bin/python3 2# 3# Copyright 2019 The ANGLE Project Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6# 7# gen_gl_enum_utils.py: 8# Generates GLenum value to string mapping for ANGLE 9# NOTE: don't run this script directly. Run scripts/run_code_generation.py. 10 11import sys 12import os 13 14import registry_xml 15 16template_gl_enums_header = """// GENERATED FILE - DO NOT EDIT. 17// Generated by {script_name} using data from {data_source_name}. 18// 19// Copyright 2019 The ANGLE Project Authors. All rights reserved. 20// Use of this source code is governed by a BSD-style license that can be 21// found in the LICENSE file. 22// 23// gl_enum_utils_autogen.h: 24// mapping of GLenum value to string. 25 26# ifndef LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_ 27# define LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_ 28 29namespace gl 30{{ 31enum class GLenumGroup 32{{ 33 {gl_enum_groups} 34}}; 35}} // namespace gl 36 37# endif // LIBANGLE_GL_ENUM_UTILS_AUTOGEN_H_ 38""" 39 40template_gl_enums_source = """// GENERATED FILE - DO NOT EDIT. 41// Generated by {script_name} using data from {data_source_name}. 42// 43// Copyright 2019 The ANGLE Project Authors. All rights reserved. 44// Use of this source code is governed by a BSD-style license that can be 45// found in the LICENSE file. 46// 47// gl_enum_utils_autogen.cpp: 48// mapping of GLenum value to string. 49 50#include "libANGLE/capture/gl_enum_utils_autogen.h" 51 52#include "libANGLE/capture/gl_enum_utils.h" 53 54namespace gl 55{{ 56namespace 57{{ 58const char *UnknownGLenumToString(unsigned int value) 59{{ 60 constexpr size_t kBufferSize = 64; 61 static thread_local char sBuffer[kBufferSize]; 62 snprintf(sBuffer, kBufferSize, "0x%04X", value); 63 return sBuffer; 64}} 65}} // anonymous namespace 66 67const char *GLenumToString(GLenumGroup enumGroup, unsigned int value) 68{{ 69 switch (enumGroup) 70 {{ 71 {gl_enums_value_to_string_table} 72 default: 73 return UnknownGLenumToString(value); 74 }} 75}} 76}} // namespace gl 77 78""" 79 80template_enum_group_case = """case GLenumGroup::{group_name}: {{ 81 switch (value) {{ 82 {inner_group_cases} 83 default: 84 return UnknownGLenumToString(value); 85 }} 86}} 87""" 88 89template_enum_value_to_string_case = """case {value}: return {name};""" 90 91exclude_gl_enums = { 92 'GL_NO_ERROR', 'GL_TIMEOUT_IGNORED', 'GL_INVALID_INDEX', 'GL_VERSION_ES_CL_1_0', 93 'GL_VERSION_ES_CM_1_1', 'GL_VERSION_ES_CL_1_1' 94} 95exclude_gl_enum_groups = {'SpecialNumbers'} 96 97 98def dump_value_to_string_mapping(gl_enum_in_groups, exporting_enums): 99 exporting_groups = list() 100 for group_name, inner_mapping in gl_enum_in_groups.items(): 101 string_value_pairs = list(filter(lambda x: x[0] in exporting_enums, inner_mapping.items())) 102 if not string_value_pairs: 103 continue 104 105 # sort according values 106 string_value_pairs.sort(key=lambda x: (x[1], x[0])) 107 108 # remove all duplicate values from the pairs list 109 # some value may have more than one GLenum mapped to them, such as: 110 # GL_DRAW_FRAMEBUFFER_BINDING and GL_FRAMEBUFFER_BINDING 111 # GL_BLEND_EQUATION_RGB and GL_BLEND_EQUATION 112 # it is safe to output either one of them, for simplity here just 113 # choose the shorter one which comes first in the sorted list 114 exporting_string_value_pairs = list() 115 for index, pair in enumerate(string_value_pairs): 116 if index == 0 or pair[1] != string_value_pairs[index - 1][1]: 117 exporting_string_value_pairs.append(pair) 118 119 inner_code_block = "\n".join([ 120 template_enum_value_to_string_case.format( 121 value='0x%X' % value, 122 name='"%s"' % name, 123 ) for name, value in exporting_string_value_pairs 124 ]) 125 126 exporting_groups.append((group_name, inner_code_block)) 127 128 return "\n".join([ 129 template_enum_group_case.format( 130 group_name=group_name, 131 inner_group_cases=inner_code_block, 132 ) for group_name, inner_code_block in sorted(exporting_groups, key=lambda x: x[0]) 133 ]) 134 135 136def main(header_output_path, source_output_path): 137 xml = registry_xml.RegistryXML('gl.xml', 'gl_angle_ext.xml') 138 139 # build a map from GLenum name to its value 140 all_gl_enums = dict() 141 for enums_node in xml.root.findall('enums'): 142 for enum in enums_node.findall('enum'): 143 name = enum.attrib['name'] 144 value = int(enum.attrib['value'], base=16) 145 all_gl_enums[name] = value 146 147 # Parse groups of GLenums to build a {group, name} -> value mapping. 148 gl_enum_in_groups = dict() 149 enums_has_group = set() 150 for enums_group_node in xml.root.findall('groups/group'): 151 group_name = enums_group_node.attrib['name'] 152 if group_name in exclude_gl_enum_groups: 153 continue 154 155 if group_name not in gl_enum_in_groups: 156 gl_enum_in_groups[group_name] = dict() 157 158 for enum_node in enums_group_node.findall('enum'): 159 enum_name = enum_node.attrib['name'] 160 enums_has_group.add(enum_name) 161 gl_enum_in_groups[group_name][enum_name] = all_gl_enums[enum_name] 162 163 # Find relevant GLenums according to enabled APIs and extensions. 164 exporting_enums = set() 165 # export all the apis 166 xpath = "./feature[@api='gles2']/require/enum" 167 for enum_tag in xml.root.findall(xpath): 168 enum_name = enum_tag.attrib['name'] 169 if enum_name not in exclude_gl_enums: 170 exporting_enums.add(enum_name) 171 172 for extension in registry_xml.supported_extensions: 173 xpath = "./extensions/extension[@name='%s']/require/enum" % extension 174 for enum_tag in xml.root.findall(xpath): 175 enum_name = enum_tag.attrib['name'] 176 if enum_name not in exclude_gl_enums: 177 exporting_enums.add(enum_name) 178 179 # For enums that do not have a group, add them to a default group 180 default_group_name = registry_xml.default_enum_group_name 181 gl_enum_in_groups[default_group_name] = dict() 182 default_group = gl_enum_in_groups[default_group_name] 183 for enum_name in exporting_enums: 184 if enum_name not in enums_has_group: 185 default_group[enum_name] = all_gl_enums[enum_name] 186 187 # Write GLenum groups into the header file. 188 header_content = template_gl_enums_header.format( 189 script_name=os.path.basename(sys.argv[0]), 190 data_source_name="gl.xml and gl_angle_ext.xml", 191 gl_enum_groups=',\n'.join(sorted(gl_enum_in_groups.keys()))) 192 193 header_output_path = registry_xml.script_relative(header_output_path) 194 with open(header_output_path, 'w') as f: 195 f.write(header_content) 196 197 # Write mapping to source file 198 gl_enums_value_to_string_table = dump_value_to_string_mapping(gl_enum_in_groups, 199 exporting_enums) 200 source_content = template_gl_enums_source.format( 201 script_name=os.path.basename(sys.argv[0]), 202 data_source_name="gl.xml and gl_angle_ext.xml", 203 gl_enums_value_to_string_table=gl_enums_value_to_string_table, 204 ) 205 206 source_output_path = registry_xml.script_relative(source_output_path) 207 with open(source_output_path, 'w') as f: 208 f.write(source_content) 209 210 return 0 211 212 213if __name__ == '__main__': 214 inputs = [ 215 'gl.xml', 216 'gl_angle_ext.xml', 217 'registry_xml.py', 218 ] 219 220 gl_enum_utils_autogen_base_path = '../src/libANGLE/capture/gl_enum_utils_autogen' 221 outputs = [ 222 gl_enum_utils_autogen_base_path + '.h', 223 gl_enum_utils_autogen_base_path + '.cpp', 224 ] 225 226 if len(sys.argv) > 1: 227 if sys.argv[1] == 'inputs': 228 print(','.join(inputs)) 229 elif sys.argv[1] == 'outputs': 230 print(','.join(outputs)) 231 else: 232 sys.exit( 233 main( 234 registry_xml.script_relative(outputs[0]), 235 registry_xml.script_relative(outputs[1]))) 236