Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 2 | |
Ian Romanick | 5f1f229 | 2005-01-07 02:39:09 +0000 | [diff] [blame] | 3 | # (C) Copyright IBM Corporation 2004, 2005 |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 4 | # All Rights Reserved. |
| 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 | # Ian Romanick <idr@us.ibm.com> |
| 27 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 28 | import libxml2 |
| 29 | import re, sys, string |
| 30 | import typeexpr |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 31 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 32 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 33 | def parse_GL_API( file_name, factory = None ): |
| 34 | doc = libxml2.readFile( file_name, None, libxml2.XML_PARSE_XINCLUDE + libxml2.XML_PARSE_NOBLANKS + libxml2.XML_PARSE_DTDVALID + libxml2.XML_PARSE_DTDATTR + libxml2.XML_PARSE_DTDLOAD + libxml2.XML_PARSE_NOENT ) |
| 35 | ret = doc.xincludeProcess() |
| 36 | |
| 37 | if not factory: |
| 38 | factory = gl_item_factory() |
| 39 | |
| 40 | api = factory.create_item( "api", None, None ) |
| 41 | api.process_element( doc ) |
| 42 | |
| 43 | doc.freeDoc() |
| 44 | |
| 45 | return api |
| 46 | |
| 47 | |
| 48 | def is_attr_true( element, name ): |
Ian Romanick | 73b4c1b | 2005-04-14 23:00:34 +0000 | [diff] [blame] | 49 | """Read a name value from an element's attributes. |
| 50 | |
| 51 | The value read from the attribute list must be either 'true' or |
| 52 | 'false'. If the value is 'false', zero will be returned. If the |
| 53 | value is 'true', non-zero will be returned. An exception will be |
| 54 | raised for any other value.""" |
| 55 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 56 | value = element.nsProp( name, None ) |
Ian Romanick | 73b4c1b | 2005-04-14 23:00:34 +0000 | [diff] [blame] | 57 | if value == "true": |
| 58 | return 1 |
| 59 | elif value == "false": |
| 60 | return 0 |
| 61 | else: |
| 62 | raise RuntimeError('Invalid value "%s" for boolean "%s".' % (value, name)) |
| 63 | |
| 64 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 65 | class gl_print_base: |
| 66 | """Base class of all API pretty-printers. |
Ian Romanick | 93d2d54 | 2005-04-18 19:42:23 +0000 | [diff] [blame] | 67 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 68 | In the model-view-controller pattern, this is the view. Any derived |
| 69 | class will want to over-ride the printBody, printRealHader, and |
| 70 | printRealFooter methods. Some derived classes may want to over-ride |
| 71 | printHeader and printFooter, or even Print (though this is unlikely). |
Ian Romanick | 93d2d54 | 2005-04-18 19:42:23 +0000 | [diff] [blame] | 72 | """ |
Ian Romanick | d03ab10 | 2005-04-18 21:30:20 +0000 | [diff] [blame] | 73 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 74 | def __init__(self): |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 75 | # Name of the script that is generating the output file. |
| 76 | # Every derived class should set this to the name of its |
| 77 | # source file. |
| 78 | |
| 79 | self.name = "a" |
| 80 | |
| 81 | |
| 82 | # License on the *generated* source file. This may differ |
| 83 | # from the license on the script that is generating the file. |
| 84 | # Every derived class should set this to some reasonable |
| 85 | # value. |
| 86 | # |
| 87 | # See license.py for an example of a reasonable value. |
| 88 | |
| 89 | self.license = "The license for this file is unspecified." |
| 90 | |
| 91 | |
| 92 | # The header_tag is the name of the C preprocessor define |
| 93 | # used to prevent multiple inclusion. Typically only |
| 94 | # generated C header files need this to be set. Setting it |
| 95 | # causes code to be generated automatically in printHeader |
| 96 | # and printFooter. |
| 97 | |
Ian Romanick | 16c3c74 | 2005-01-28 19:00:54 +0000 | [diff] [blame] | 98 | self.header_tag = None |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 99 | |
| 100 | |
| 101 | # List of file-private defines that must be undefined at the |
| 102 | # end of the file. This can be used in header files to define |
| 103 | # names for use in the file, then undefine them at the end of |
| 104 | # the header file. |
| 105 | |
Ian Romanick | c280358 | 2005-02-01 00:28:47 +0000 | [diff] [blame] | 106 | self.undef_list = [] |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 107 | return |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 108 | |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 109 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 110 | def Print(self, api): |
| 111 | self.printHeader() |
| 112 | self.printBody(api) |
| 113 | self.printFooter() |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 114 | return |
| 115 | |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 116 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 117 | def printHeader(self): |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 118 | """Print the header associated with all files and call the printRealHeader method.""" |
| 119 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 120 | print '/* DO NOT EDIT - This file generated automatically by %s script */' \ |
| 121 | % (self.name) |
| 122 | print '' |
| 123 | print '/*' |
| 124 | print ' * ' + self.license.replace('\n', '\n * ') |
| 125 | print ' */' |
| 126 | print '' |
Ian Romanick | 16c3c74 | 2005-01-28 19:00:54 +0000 | [diff] [blame] | 127 | if self.header_tag: |
| 128 | print '#if !defined( %s )' % (self.header_tag) |
| 129 | print '# define %s' % (self.header_tag) |
| 130 | print '' |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 131 | self.printRealHeader(); |
| 132 | return |
| 133 | |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 134 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 135 | def printFooter(self): |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 136 | """Print the header associated with all files and call the printRealFooter method.""" |
| 137 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 138 | self.printRealFooter() |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 139 | |
| 140 | if self.undef_list: |
| 141 | print '' |
| 142 | for u in self.undef_list: |
| 143 | print "# undef %s" % (u) |
| 144 | |
Ian Romanick | 16c3c74 | 2005-01-28 19:00:54 +0000 | [diff] [blame] | 145 | if self.header_tag: |
Ian Romanick | c280358 | 2005-02-01 00:28:47 +0000 | [diff] [blame] | 146 | print '' |
| 147 | print '#endif /* !defined( %s ) */' % (self.header_tag) |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 148 | |
| 149 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 150 | def printRealHeader(self): |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 151 | """Print the "real" header for the created file. |
| 152 | |
| 153 | In the base class, this function is empty. All derived |
| 154 | classes should over-ride this function.""" |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 155 | return |
| 156 | |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 157 | |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 158 | def printRealFooter(self): |
Ian Romanick | a9d033c | 2004-05-19 23:33:08 +0000 | [diff] [blame] | 159 | """Print the "real" footer for the created file. |
| 160 | |
| 161 | In the base class, this function is empty. All derived |
| 162 | classes should over-ride this function.""" |
Ian Romanick | 73f59b0 | 2004-05-18 18:33:40 +0000 | [diff] [blame] | 163 | return |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 164 | |
| 165 | |
| 166 | def printPure(self): |
| 167 | """Conditionally define `PURE' function attribute. |
| 168 | |
| 169 | Conditionally defines a preprocessor macro `PURE' that wraps |
| 170 | GCC's `pure' function attribute. The conditional code can be |
| 171 | easilly adapted to other compilers that support a similar |
| 172 | feature. |
| 173 | |
| 174 | The name is also added to the file's undef_list. |
| 175 | """ |
| 176 | self.undef_list.append("PURE") |
| 177 | print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) |
| 178 | # define PURE __attribute__((pure)) |
| 179 | # else |
| 180 | # define PURE |
| 181 | # endif""" |
| 182 | return |
| 183 | |
| 184 | |
| 185 | def printFastcall(self): |
| 186 | """Conditionally define `FASTCALL' function attribute. |
| 187 | |
| 188 | Conditionally defines a preprocessor macro `FASTCALL' that |
| 189 | wraps GCC's `fastcall' function attribute. The conditional |
| 190 | code can be easilly adapted to other compilers that support a |
| 191 | similar feature. |
| 192 | |
| 193 | The name is also added to the file's undef_list. |
| 194 | """ |
| 195 | |
| 196 | self.undef_list.append("FASTCALL") |
Brian Paul | f468dfd | 2005-10-20 22:51:50 +0000 | [diff] [blame^] | 197 | print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__) |
| 198 | # define FASTCALL __attribute__((fastcall)) |
| 199 | # else |
| 200 | # define FASTCALL |
| 201 | # endif""" |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 202 | return |
| 203 | |
| 204 | |
| 205 | def printVisibility(self, S, s): |
| 206 | """Conditionally define visibility function attribute. |
| 207 | |
| 208 | Conditionally defines a preprocessor macro name S that wraps |
| 209 | GCC's visibility function attribute. The visibility used is |
| 210 | the parameter s. The conditional code can be easilly adapted |
| 211 | to other compilers that support a similar feature. |
| 212 | |
| 213 | The name is also added to the file's undef_list. |
| 214 | """ |
| 215 | |
| 216 | self.undef_list.append(S) |
Adam Jackson | ca1ac98 | 2005-08-26 17:50:39 +0000 | [diff] [blame] | 217 | print """# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 218 | # define %s __attribute__((visibility("%s"))) |
| 219 | # else |
| 220 | # define %s |
| 221 | # endif""" % (S, s, S) |
| 222 | return |
| 223 | |
| 224 | |
| 225 | def printNoinline(self): |
| 226 | """Conditionally define `NOINLINE' function attribute. |
| 227 | |
| 228 | Conditionally defines a preprocessor macro `NOINLINE' that |
| 229 | wraps GCC's `noinline' function attribute. The conditional |
| 230 | code can be easilly adapted to other compilers that support a |
| 231 | similar feature. |
| 232 | |
| 233 | The name is also added to the file's undef_list. |
| 234 | """ |
| 235 | |
| 236 | self.undef_list.append("NOINLINE") |
| 237 | print """# if defined(__GNUC__) |
| 238 | # define NOINLINE __attribute__((noinline)) |
| 239 | # else |
| 240 | # define NOINLINE |
| 241 | # endif""" |
| 242 | return |
| 243 | |
| 244 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 245 | def real_function_name(element): |
| 246 | name = element.nsProp( "name", None ) |
| 247 | alias = element.nsProp( "alias", None ) |
| 248 | |
| 249 | if alias: |
| 250 | return alias |
| 251 | else: |
| 252 | return name |
| 253 | |
| 254 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 255 | def real_category_name(c): |
| 256 | if re.compile("[1-9][0-9]*[.][0-9]+").match(c): |
| 257 | return "GL_VERSION_" + c.replace(".", "_") |
| 258 | else: |
| 259 | return c |
| 260 | |
| 261 | |
Ian Romanick | f0ff50d | 2005-07-02 08:29:57 +0000 | [diff] [blame] | 262 | def create_parameter_string(parameters, include_names): |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 263 | """Create a parameter string from a list of gl_parameters.""" |
| 264 | |
| 265 | list = [] |
| 266 | for p in parameters: |
Ian Romanick | f0ff50d | 2005-07-02 08:29:57 +0000 | [diff] [blame] | 267 | if include_names: |
| 268 | list.append( p.string() ) |
| 269 | else: |
| 270 | list.append( p.type_string() ) |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 271 | |
| 272 | if len(list) == 0: list = ["void"] |
| 273 | |
| 274 | return string.join(list, ", ") |
| 275 | |
| 276 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 277 | class gl_item: |
| 278 | def __init__(self, element, context): |
| 279 | self.context = context |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 280 | self.name = element.nsProp( "name", None ) |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 281 | self.category = real_category_name( element.parent.nsProp( "name", None ) ) |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 282 | return |
| 283 | |
| 284 | |
| 285 | class gl_type( gl_item ): |
| 286 | def __init__(self, element, context): |
| 287 | gl_item.__init__(self, element, context) |
| 288 | self.size = int( element.nsProp( "size", None ), 0 ) |
| 289 | |
| 290 | te = typeexpr.type_expression( None ) |
| 291 | tn = typeexpr.type_node() |
| 292 | tn.size = int( element.nsProp( "size", None ), 0 ) |
| 293 | tn.integer = not is_attr_true( element, "float" ) |
| 294 | tn.unsigned = is_attr_true( element, "unsigned" ) |
| 295 | tn.name = "GL" + self.name |
| 296 | te.set_base_type_node( tn ) |
| 297 | |
| 298 | self.type_expr = te |
| 299 | return |
| 300 | |
| 301 | |
| 302 | def get_type_expression(self): |
| 303 | return self.type_expr |
| 304 | |
| 305 | |
| 306 | class gl_enum( gl_item ): |
| 307 | def __init__(self, element, context): |
| 308 | gl_item.__init__(self, element, context) |
| 309 | self.value = int( element.nsProp( "value", None ), 0 ) |
| 310 | |
| 311 | temp = element.nsProp( "count", None ) |
| 312 | if not temp or temp == "?": |
| 313 | self.default_count = -1 |
| 314 | else: |
| 315 | try: |
| 316 | c = int(temp) |
| 317 | except Exception,e: |
| 318 | raise RuntimeError('Invalid count value "%s" for enum "%s" in function "%s" when an integer was expected.' % (temp, self.name, n)) |
| 319 | |
| 320 | self.default_count = c |
| 321 | |
| 322 | return |
| 323 | |
| 324 | |
| 325 | def priority(self): |
| 326 | """Calculate a 'priority' for this enum name. |
| 327 | |
| 328 | When an enum is looked up by number, there may be many |
| 329 | possible names, but only one is the 'prefered' name. The |
| 330 | priority is used to select which name is the 'best'. |
| 331 | |
| 332 | Highest precedence is given to core GL name. ARB extension |
| 333 | names have the next highest, followed by EXT extension names. |
| 334 | Vendor extension names are the lowest. |
| 335 | """ |
| 336 | |
| 337 | if self.name.endswith( "_BIT" ): |
| 338 | bias = 1 |
| 339 | else: |
| 340 | bias = 0 |
| 341 | |
| 342 | if self.category.startswith( "GL_VERSION_" ): |
| 343 | priority = 0 |
| 344 | elif self.category.startswith( "GL_ARB_" ): |
| 345 | priority = 2 |
| 346 | elif self.category.startswith( "GL_EXT_" ): |
| 347 | priority = 4 |
| 348 | else: |
| 349 | priority = 6 |
| 350 | |
| 351 | return priority + bias |
| 352 | |
| 353 | |
| 354 | |
| 355 | class gl_parameter: |
| 356 | def __init__(self, element, context): |
| 357 | self.name = element.nsProp( "name", None ) |
| 358 | |
| 359 | ts = element.nsProp( "type", None ) |
| 360 | self.type_expr = typeexpr.type_expression( ts, context ) |
| 361 | |
| 362 | temp = element.nsProp( "variable_param", None ) |
| 363 | if temp: |
| 364 | self.count_parameter_list = temp.split( ' ' ) |
| 365 | else: |
| 366 | self.count_parameter_list = [] |
| 367 | |
| 368 | # The count tag can be either a numeric string or the name of |
| 369 | # a variable. If it is the name of a variable, the int(c) |
| 370 | # statement will throw an exception, and the except block will |
| 371 | # take over. |
| 372 | |
| 373 | c = element.nsProp( "count", None ) |
| 374 | try: |
| 375 | count = int(c) |
| 376 | self.count = count |
| 377 | self.counter = None |
| 378 | except Exception,e: |
| 379 | count = 1 |
| 380 | self.count = 0 |
| 381 | self.counter = c |
| 382 | |
| 383 | self.count_scale = int(element.nsProp( "count_scale", None )) |
| 384 | |
| 385 | elements = (count * self.count_scale) |
| 386 | if elements == 1: |
| 387 | elements = 0 |
| 388 | |
| 389 | #if ts == "GLdouble": |
| 390 | # print '/* stack size -> %s = %u (before)*/' % (self.name, self.type_expr.get_stack_size()) |
| 391 | # print '/* # elements = %u */' % (elements) |
| 392 | self.type_expr.set_elements( elements ) |
| 393 | #if ts == "GLdouble": |
| 394 | # print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size()) |
| 395 | |
| 396 | self.is_counter = is_attr_true( element, 'counter' ) |
| 397 | self.is_output = is_attr_true( element, 'output' ) |
| 398 | |
| 399 | |
| 400 | # Pixel data has special parameters. |
| 401 | |
| 402 | self.width = element.nsProp('img_width', None) |
| 403 | self.height = element.nsProp('img_height', None) |
| 404 | self.depth = element.nsProp('img_depth', None) |
| 405 | self.extent = element.nsProp('img_extent', None) |
| 406 | |
| 407 | self.img_xoff = element.nsProp('img_xoff', None) |
| 408 | self.img_yoff = element.nsProp('img_yoff', None) |
| 409 | self.img_zoff = element.nsProp('img_zoff', None) |
| 410 | self.img_woff = element.nsProp('img_woff', None) |
| 411 | |
| 412 | self.img_format = element.nsProp('img_format', None) |
| 413 | self.img_type = element.nsProp('img_type', None) |
| 414 | self.img_target = element.nsProp('img_target', None) |
| 415 | |
| 416 | self.img_pad_dimensions = is_attr_true( element, 'img_pad_dimensions' ) |
| 417 | self.img_null_flag = is_attr_true( element, 'img_null_flag' ) |
| 418 | self.img_send_null = is_attr_true( element, 'img_send_null' ) |
| 419 | |
| 420 | return |
| 421 | |
| 422 | |
| 423 | def compatible(self, other): |
| 424 | return 1 |
| 425 | |
| 426 | |
| 427 | def is_array(self): |
| 428 | return self.is_pointer() |
| 429 | |
| 430 | |
| 431 | def is_pointer(self): |
| 432 | return self.type_expr.is_pointer() |
| 433 | |
| 434 | |
| 435 | def is_image(self): |
| 436 | if self.width: |
| 437 | return 1 |
| 438 | else: |
| 439 | return 0 |
| 440 | |
| 441 | |
| 442 | def is_variable_length(self): |
| 443 | return len(self.count_parameter_list) or self.counter |
| 444 | |
| 445 | |
| 446 | def is_64_bit(self): |
| 447 | count = self.type_expr.get_element_count() |
| 448 | if count: |
| 449 | if (self.size() / count) == 8: |
| 450 | return 1 |
| 451 | else: |
| 452 | if self.size() == 8: |
| 453 | return 1 |
| 454 | |
| 455 | return 0 |
| 456 | |
| 457 | |
| 458 | def string(self): |
| 459 | return self.type_expr.original_string + " " + self.name |
| 460 | |
| 461 | |
| 462 | def type_string(self): |
| 463 | return self.type_expr.original_string |
| 464 | |
| 465 | |
| 466 | def get_base_type_string(self): |
| 467 | return self.type_expr.get_base_name() |
| 468 | |
| 469 | |
| 470 | def get_dimensions(self): |
| 471 | if not self.width: |
| 472 | return [ 0, "0", "0", "0", "0" ] |
| 473 | |
| 474 | dim = 1 |
| 475 | w = self.width |
| 476 | h = "1" |
| 477 | d = "1" |
| 478 | e = "1" |
| 479 | |
| 480 | if self.height: |
| 481 | dim = 2 |
| 482 | h = self.height |
| 483 | |
| 484 | if self.depth: |
| 485 | dim = 3 |
| 486 | d = self.depth |
| 487 | |
| 488 | if self.extent: |
| 489 | dim = 4 |
| 490 | e = self.extent |
| 491 | |
| 492 | return [ dim, w, h, d, e ] |
| 493 | |
| 494 | |
| 495 | def get_stack_size(self): |
| 496 | return self.type_expr.get_stack_size() |
| 497 | |
| 498 | |
| 499 | def size(self): |
| 500 | if self.is_image(): |
| 501 | return 0 |
| 502 | else: |
| 503 | return self.type_expr.get_element_size() |
| 504 | |
| 505 | |
| 506 | def get_element_count(self): |
| 507 | c = self.type_expr.get_element_count() |
| 508 | if c == 0: |
| 509 | return 1 |
| 510 | |
| 511 | return c |
| 512 | |
| 513 | |
| 514 | def size_string(self, use_parens = 1): |
| 515 | s = self.size() |
| 516 | if self.counter or self.count_parameter_list: |
| 517 | list = [ "compsize" ] |
| 518 | |
| 519 | if self.counter and self.count_parameter_list: |
| 520 | list.append( self.counter ) |
| 521 | elif self.counter: |
| 522 | list = [ self.counter ] |
| 523 | |
| 524 | if s > 1: |
| 525 | list.append( str(s) ) |
| 526 | |
| 527 | if len(list) > 1 and use_parens : |
| 528 | return "(%s)" % (string.join(list, " * ")) |
| 529 | else: |
| 530 | return string.join(list, " * ") |
| 531 | |
| 532 | elif self.is_image(): |
| 533 | return "compsize" |
| 534 | else: |
| 535 | return str(s) |
| 536 | |
| 537 | |
| 538 | def format_string(self): |
| 539 | if self.type_expr.original_string == "GLenum": |
| 540 | return "0x%x" |
| 541 | else: |
| 542 | return self.type_expr.format_string() |
| 543 | |
| 544 | |
| 545 | |
| 546 | class gl_function( gl_item ): |
| 547 | def __init__(self, element, context): |
| 548 | self.context = context |
| 549 | self.name = None |
| 550 | |
| 551 | self.entry_points = [] |
| 552 | self.return_type = "void" |
| 553 | self.parameters = [] |
| 554 | self.offset = -1 |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 555 | self.initialized = 0 |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 556 | self.images = [] |
| 557 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 558 | # Track the parameter string (for the function prototype) |
| 559 | # for each entry-point. This is done because some functions |
| 560 | # change their prototype slightly when promoted from extension |
| 561 | # to ARB extension to core. glTexImage3DEXT and glTexImage3D |
| 562 | # are good examples of this. Scripts that need to generate |
| 563 | # code for these differing aliases need to real prototype |
| 564 | # for each entry-point. Otherwise, they may generate code |
| 565 | # that won't compile. |
| 566 | |
| 567 | self.parameter_strings = {} |
| 568 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 569 | self.process_element( element ) |
| 570 | |
| 571 | return |
| 572 | |
| 573 | |
| 574 | def process_element(self, element): |
| 575 | name = element.nsProp( "name", None ) |
| 576 | alias = element.nsProp( "alias", None ) |
| 577 | |
| 578 | self.entry_points.append( name ) |
| 579 | if alias: |
| 580 | true_name = alias |
| 581 | else: |
| 582 | true_name = name |
| 583 | |
| 584 | # Only try to set the offset when a non-alias |
| 585 | # entry-point is being processes. |
| 586 | |
| 587 | offset = element.nsProp( "offset", None ) |
| 588 | if offset: |
| 589 | try: |
| 590 | o = int( offset ) |
| 591 | self.offset = o |
| 592 | except Exception, e: |
| 593 | self.offset = -1 |
| 594 | |
| 595 | |
| 596 | if not self.name: |
| 597 | self.name = true_name |
| 598 | elif self.name != true_name: |
| 599 | raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name)) |
| 600 | |
| 601 | |
| 602 | # There are two possible cases. The first time an entry-point |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 603 | # with data is seen, self.initialized will be 0. On that |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 604 | # pass, we just fill in the data. The next time an |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 605 | # entry-point with data is seen, self.initialized will be 1. |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 606 | # On that pass we have to make that the new values match the |
| 607 | # valuse from the previous entry-point. |
| 608 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 609 | parameters = [] |
| 610 | return_type = "void" |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 611 | child = element.children |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 612 | while child: |
| 613 | if child.type == "element": |
| 614 | if child.name == "return": |
| 615 | return_type = child.nsProp( "type", None ) |
| 616 | elif child.name == "param": |
| 617 | param = self.context.factory.create_item( "parameter", child, self.context) |
| 618 | parameters.append( param ) |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 619 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 620 | child = child.next |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 621 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 622 | |
| 623 | if self.initialized: |
| 624 | if self.return_type != return_type: |
| 625 | raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type)) |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 626 | |
| 627 | if len(parameters) != len(self.parameters): |
| 628 | raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters))) |
| 629 | |
| 630 | for j in range(0, len(parameters)): |
| 631 | p1 = parameters[j] |
| 632 | p2 = self.parameters[j] |
| 633 | if not p1.compatible( p2 ): |
| 634 | raise RuntimeError( 'Parameter type mismatch in %s. "%s" was "%s", now "%s".' % (name, p2.name, p2.type_expr.original_string, p1.type_expr.original_string)) |
| 635 | |
| 636 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 637 | if true_name == name or not self.initialized: |
| 638 | self.return_type = return_type |
| 639 | self.parameters = parameters |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 640 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 641 | for param in self.parameters: |
| 642 | if param.is_image(): |
| 643 | self.images.append( param ) |
| 644 | |
| 645 | if element.children: |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 646 | self.initialized = 1 |
Ian Romanick | f0ff50d | 2005-07-02 08:29:57 +0000 | [diff] [blame] | 647 | self.parameter_strings[name] = create_parameter_string(parameters, 1) |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 648 | else: |
| 649 | self.parameter_strings[name] = None |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 650 | |
| 651 | return |
| 652 | |
| 653 | |
| 654 | def get_images(self): |
| 655 | """Return potentially empty list of input images.""" |
| 656 | return self.images |
| 657 | |
| 658 | |
| 659 | def parameterIterator(self): |
| 660 | return self.parameters.__iter__(); |
| 661 | |
| 662 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 663 | def get_parameter_string(self, entrypoint = None): |
| 664 | if entrypoint: |
| 665 | s = self.parameter_strings[ entrypoint ] |
| 666 | if s: |
| 667 | return s |
| 668 | |
Ian Romanick | f0ff50d | 2005-07-02 08:29:57 +0000 | [diff] [blame] | 669 | return create_parameter_string( self.parameters, 1 ) |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 670 | |
| 671 | |
| 672 | class gl_item_factory: |
| 673 | """Factory to create objects derived from gl_item.""" |
| 674 | |
| 675 | def create_item(self, item_name, element, context): |
| 676 | if item_name == "function": |
| 677 | return gl_function(element, context) |
| 678 | if item_name == "type": |
| 679 | return gl_type(element, context) |
| 680 | elif item_name == "enum": |
| 681 | return gl_enum(element, context) |
| 682 | elif item_name == "parameter": |
| 683 | return gl_parameter(element, context) |
| 684 | elif item_name == "api": |
| 685 | return gl_api(self) |
| 686 | else: |
| 687 | return None |
| 688 | |
| 689 | |
| 690 | class gl_api: |
| 691 | def __init__(self, factory): |
| 692 | self.functions_by_name = {} |
| 693 | self.enums_by_name = {} |
| 694 | self.types_by_name = {} |
| 695 | self.category_dict = {} |
| 696 | |
| 697 | self.factory = factory |
| 698 | |
| 699 | typeexpr.create_initial_types() |
| 700 | return |
| 701 | |
| 702 | |
| 703 | def process_element(self, doc): |
| 704 | element = doc.children |
| 705 | while element.type != "element" or element.name != "OpenGLAPI": |
| 706 | element = element.next |
| 707 | |
| 708 | if element: |
| 709 | self.process_OpenGLAPI(element) |
| 710 | return |
| 711 | |
| 712 | |
| 713 | def process_OpenGLAPI(self, element): |
| 714 | child = element.children |
| 715 | while child: |
| 716 | if child.type == "element": |
| 717 | if child.name == "category": |
| 718 | self.process_category( child ) |
| 719 | elif child.name == "OpenGLAPI": |
| 720 | self.process_OpenGLAPI( child ) |
| 721 | |
| 722 | child = child.next |
| 723 | |
| 724 | return |
| 725 | |
| 726 | |
| 727 | def process_category(self, cat): |
| 728 | cat_name = cat.nsProp( "name", None ) |
| 729 | cat_number = cat.nsProp( "number", None ) |
| 730 | |
| 731 | child = cat.children |
| 732 | while child: |
| 733 | if child.type == "element": |
| 734 | if child.name == "function": |
| 735 | func_name = real_function_name( child ) |
| 736 | |
Ian Romanick | 5aafea0 | 2005-06-24 18:35:31 +0000 | [diff] [blame] | 737 | temp_name = child.nsProp( "name", None ) |
| 738 | self.category_dict[ temp_name ] = [cat_name, cat_number] |
| 739 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 740 | if self.functions_by_name.has_key( func_name ): |
| 741 | func = self.functions_by_name[ func_name ] |
| 742 | func.process_element( child ) |
| 743 | else: |
| 744 | func = self.factory.create_item( "function", child, self ) |
| 745 | self.functions_by_name[ func_name ] = func |
| 746 | |
Ian Romanick | 66a5548 | 2005-06-21 23:42:43 +0000 | [diff] [blame] | 747 | |
| 748 | elif child.name == "enum": |
| 749 | enum = self.factory.create_item( "enum", child, self ) |
| 750 | self.enums_by_name[ enum.name ] = enum |
| 751 | elif child.name == "type": |
| 752 | t = self.factory.create_item( "type", child, self ) |
| 753 | self.types_by_name[ "GL" + t.name ] = t |
| 754 | |
| 755 | |
| 756 | child = child.next |
| 757 | |
| 758 | return |
| 759 | |
| 760 | |
| 761 | def functionIterateByOffset(self): |
| 762 | max_offset = -1 |
| 763 | for func in self.functions_by_name.itervalues(): |
| 764 | if func.offset > max_offset: |
| 765 | max_offset = func.offset |
| 766 | |
| 767 | |
| 768 | temp = [None for i in range(0, max_offset + 1)] |
| 769 | for func in self.functions_by_name.itervalues(): |
| 770 | if func.offset != -1: |
| 771 | temp[ func.offset ] = func |
| 772 | |
| 773 | |
| 774 | list = [] |
| 775 | for i in range(0, max_offset + 1): |
| 776 | if temp[i]: |
| 777 | list.append(temp[i]) |
| 778 | |
| 779 | return list.__iter__(); |
| 780 | |
| 781 | |
| 782 | def functionIterateAll(self): |
| 783 | return self.functions_by_name.itervalues() |
| 784 | |
| 785 | |
| 786 | def enumIterateByName(self): |
| 787 | keys = self.enums_by_name.keys() |
| 788 | keys.sort() |
| 789 | |
| 790 | list = [] |
| 791 | for enum in keys: |
| 792 | list.append( self.enums_by_name[ enum ] ) |
| 793 | |
| 794 | return list.__iter__() |
| 795 | |
| 796 | |
| 797 | def get_category_for_name( self, name ): |
| 798 | if self.category_dict.has_key(name): |
| 799 | return self.category_dict[name] |
| 800 | else: |
| 801 | return ["<unknown category>", None] |
| 802 | |
| 803 | |
| 804 | def typeIterate(self): |
| 805 | return self.types_by_name.itervalues() |
| 806 | |
| 807 | |
| 808 | def find_type( self, type_name ): |
| 809 | if type_name in self.types_by_name: |
| 810 | return self.types_by_name[ type_name ].type_expr |
| 811 | else: |
| 812 | print "Unable to find base type matching \"%s\"." % (type_name) |
| 813 | return None |