1 2# (C) Copyright Zack Rusin 2005. All Rights Reserved. 3# Copyright (C) 2015 Intel Corporation 4# Copyright (C) 2015 Broadcom Corporation 5# 6# Permission is hereby granted, free of charge, to any person obtaining a 7# copy of this software and associated documentation files (the "Software"), 8# to deal in the Software without restriction, including without limitation 9# on the rights to use, copy, modify, merge, publish, distribute, sub 10# license, and/or sell copies of the Software, and to permit persons to whom 11# the Software is furnished to do so, subject to the following conditions: 12# 13# The above copyright notice and this permission notice (including the next 14# paragraph) shall be included in all copies or substantial portions of the 15# Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 20# IBM AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 23# IN THE SOFTWARE. 24# 25# Authors: 26# Zack Rusin <zack@kde.org> 27 28import argparse 29 30import license 31import gl_XML 32import xml.etree.ElementTree as ET 33import sys, getopt 34import re 35 36class PrintGlEnums(gl_XML.gl_print_base): 37 38 def __init__(self): 39 gl_XML.gl_print_base.__init__(self) 40 41 self.name = "gl_enums.py (from Mesa)" 42 self.license = license.bsd_license_template % ( \ 43"""Copyright (C) 1999-2005 Brian Paul All Rights Reserved.""", "BRIAN PAUL") 44 # Mapping from enum value to (name, priority) tuples. 45 self.enum_table = {} 46 # Mapping from enum name to value 47 self.string_to_int = {} 48 49 50 def printRealHeader(self): 51 print('#include <stdio.h>') 52 print('#include "main/glheader.h"') 53 print('#include "main/enums.h"') 54 print('#include "main/mtypes.h"') 55 print('') 56 print('typedef struct PACKED {') 57 print(' uint32_t offset;') 58 print(' int n;') 59 print('} enum_elt;') 60 print('') 61 return 62 63 def print_code(self): 64 print(""" 65typedef int (*cfunc)(const void *, const void *); 66 67/** 68 * Compare a key enum value to an element in the \c enum_string_table_offsets array. 69 * 70 * \c bsearch always passes the key as the first parameter and the pointer 71 * to the array element as the second parameter. We can elimiate some 72 * extra work by taking advantage of that fact. 73 * 74 * \param a Pointer to the desired enum name. 75 * \param b Pointer into the \c enum_string_table_offsets array. 76 */ 77static int compar_nr( const int *a, enum_elt *b ) 78{ 79 return a[0] - b->n; 80} 81 82 83static char token_tmp[20]; 84 85/** 86 * This function always returns a string. If the number is a valid enum, it 87 * returns the enum name. Otherwise, it returns a numeric string. 88 */ 89const char * 90_mesa_enum_to_string(int nr) 91{ 92 enum_elt *elt; 93 94 elt = bsearch(& nr, enum_string_table_offsets, 95 ARRAY_SIZE(enum_string_table_offsets), 96 sizeof(enum_string_table_offsets[0]), 97 (cfunc) compar_nr); 98 99 if (elt != NULL) { 100 return &enum_string_table[elt->offset]; 101 } 102 else { 103 /* this is not re-entrant safe, no big deal here */ 104 snprintf(token_tmp, sizeof(token_tmp) - 1, "0x%x", nr); 105 token_tmp[sizeof(token_tmp) - 1] = '\\0'; 106 return token_tmp; 107 } 108} 109 110/** 111 * Primitive names 112 */ 113static const char *prim_names[PRIM_MAX+3] = { 114 "GL_POINTS", 115 "GL_LINES", 116 "GL_LINE_LOOP", 117 "GL_LINE_STRIP", 118 "GL_TRIANGLES", 119 "GL_TRIANGLE_STRIP", 120 "GL_TRIANGLE_FAN", 121 "GL_QUADS", 122 "GL_QUAD_STRIP", 123 "GL_POLYGON", 124 "GL_LINES_ADJACENCY", 125 "GL_LINE_STRIP_ADJACENCY", 126 "GL_TRIANGLES_ADJACENCY", 127 "GL_TRIANGLE_STRIP_ADJACENCY", 128 "GL_PATCHES", 129 "outside begin/end", 130 "unknown state" 131}; 132 133 134/* Get the name of an enum given that it is a primitive type. Avoids 135 * GL_FALSE/GL_POINTS ambiguity and others. 136 */ 137const char * 138_mesa_lookup_prim_by_nr(GLuint nr) 139{ 140 if (nr < ARRAY_SIZE(prim_names)) 141 return prim_names[nr]; 142 else 143 return "invalid mode"; 144} 145 146 147""") 148 return 149 150 151 def printBody(self, xml): 152 self.process_enums(xml) 153 154 sorted_enum_values = sorted(self.enum_table.keys()) 155 string_offsets = {} 156 i = 0; 157 print('#if defined(__GNUC__)') 158 print('# define LONGSTRING __extension__') 159 print('#else') 160 print('# define LONGSTRING') 161 print('#endif') 162 print('') 163 print('LONGSTRING static const char enum_string_table[] = {') 164 # We express the very long concatenation of enum strings as an array 165 # of characters rather than as a string literal to work-around MSVC's 166 # 65535 character limit. 167 for enum in sorted_enum_values: 168 (name, pri) = self.enum_table[enum] 169 print(" ", end=' ') 170 for ch in name: 171 print("'%c'," % ch, end=' ') 172 print("'\\0',") 173 174 string_offsets[ enum ] = i 175 i += len(name) + 1 176 177 print('};') 178 print('') 179 180 181 print('static const enum_elt enum_string_table_offsets[%u] =' % (len(self.enum_table))) 182 print('{') 183 for enum in sorted_enum_values: 184 (name, pri) = self.enum_table[enum] 185 print(' { %5u, 0x%08X }, /* %s */' % (string_offsets[enum], enum, name)) 186 print('};') 187 print('') 188 189 self.print_code() 190 return 191 192 def add_enum_provider(self, name, priority): 193 value = self.string_to_int[name] 194 195 # We don't want the weird GL_SKIP_COMPONENTS1_NV enums. 196 if value < 0: 197 return 198 # We don't want the 64-bit GL_TIMEOUT_IGNORED "enums" 199 if value > 0xffffffff: 200 return 201 202 # We don't want bitfields in the enum-to-string table -- 203 # individual bits have so many names, it's pointless. Note 204 # that we check for power-of-two, since some getters have 205 # "_BITS" in their name, but none have a power-of-two enum 206 # number. 207 if not (value & (value - 1)) and '_BIT' in name: 208 return 209 210 # Also drop the GL_*_ATTRIB_BITS bitmasks. 211 if value == 0xffffffff: 212 return 213 214 if value in self.enum_table: 215 (n, p) = self.enum_table[value] 216 if priority < p: 217 self.enum_table[value] = (name, priority) 218 else: 219 self.enum_table[value] = (name, priority) 220 221 def process_extension(self, extension): 222 if extension.get('name').startswith('GL_ARB_'): 223 extension_prio = 400 224 elif extension.get('name').startswith('GL_EXT_'): 225 extension_prio = 600 226 else: 227 extension_prio = 800 228 229 for enum in extension.findall('require/enum'): 230 self.add_enum_provider(enum.get('name'), extension_prio) 231 232 def process_enums(self, xml): 233 # First, process the XML entries that define the hex values 234 # for all of the enum names. 235 for enum in xml.findall('enums/enum'): 236 name = enum.get('name') 237 value = int(enum.get('value'), base=16) 238 239 # If the same name ever maps to multiple values, that can 240 # confuse us. GL_ACTIVE_PROGRAM_EXT is OK to lose because 241 # we choose GL_ACTIVE PROGRAM instead. 242 if name in self.string_to_int and name != "GL_ACTIVE_PROGRAM_EXT": 243 print("#error Renumbering {0} from {1} to {2}".format(name, self.string_to_int[name], value)) 244 245 self.string_to_int[name] = value 246 247 # Now, process all of the API versions and extensions that 248 # provide enums, so we can decide what name to call any hex 249 # value. 250 for feature in xml.findall('feature'): 251 feature_name = feature.get('name') 252 253 # When an enum gets renamed in a newer version (generally 254 # because of some generalization of the functionality), 255 # prefer the newer name. Also, prefer desktop GL names to 256 # ES. 257 m = re.match('GL_VERSION_([0-9])_([0-9])', feature_name) 258 if m: 259 feature_prio = 100 - int(m.group(1) + m.group(2)) 260 else: 261 m = re.match('GL_ES_VERSION_([0-9])_([0-9])', feature_name) 262 if m: 263 feature_prio = 200 - int(m.group(1) + m.group(2)) 264 else: 265 feature_prio = 200 266 267 for enum in feature.findall('require/enum'): 268 self.add_enum_provider(enum.get('name'), feature_prio) 269 270 for extension in xml.findall('extensions/extension'): 271 self.process_extension(extension) 272 273 274def _parser(): 275 parser = argparse.ArgumentParser() 276 parser.add_argument('-f', '--input_file', 277 required=True, 278 help="Choose an xml file to parse.") 279 return parser.parse_args() 280 281 282def main(): 283 args = _parser() 284 xml = ET.parse(args.input_file) 285 286 printer = PrintGlEnums() 287 printer.Print(xml) 288 289 290if __name__ == '__main__': 291 main() 292