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