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