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