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