api = factory.create_item( "api", None, None )
api.process_element( doc )
+ # After the XML has been processed, we need to go back and assign
+ # dispatch offsets to the functions that request that their offsets
+ # be assigned by the scripts. Typically this means all functions
+ # that are not part of the ABI.
+
+ for func in api.functionIterateByCategory():
+ if func.assign_offset:
+ func.offset = api.next_offset;
+ api.next_offset += 1
+
doc.freeDoc()
return api
"""
self.undef_list.append("FASTCALL")
- print """# if defined(__i386__) && defined(__GNUC__)
+ print """# if defined(__i386__) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
# define FASTCALL __attribute__((fastcall))
# else
# define FASTCALL
"""
self.undef_list.append(S)
- print """# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+ print """# if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__)
# define %s __attribute__((visibility("%s")))
# else
# define %s
return
- def printHaveAlias(self):
- """Conditionally define `HAVE_ALIAS'.
-
- Conditionally defines a preprocessor macro `HAVE_ALIAS'. The
- existance of this macro can be used to determine whether or
- not GCC's alias function attribute can be used.
-
- The name is also added to the file's undef_list.
- """
-
- self.undef_list.append("HAVE_ALIAS")
- print """# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
-# define HAVE_ALIAS
-# endif"""
- return
-
-
def real_function_name(element):
name = element.nsProp( "name", None )
alias = element.nsProp( "alias", None )
return name
-class gl_item:
- def __init__(self, element, context):
- self.context = context
+def real_category_name(c):
+ if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
+ return "GL_VERSION_" + c.replace(".", "_")
+ else:
+ return c
- self.name = element.nsProp( "name", None )
- c = element.parent.nsProp( "name", None )
- if re.compile("[1-9][0-9]*[.][0-9]+").match(c):
- self.category = "GL_VERSION_" + c.replace(".", "_")
+def classify_category(name, number):
+ """Based on the category name and number, select a numerical class for it.
+
+ Categories are divided into four classes numbered 0 through 3. The
+ classes are:
+
+ 0. Core GL versions, sorted by version number.
+ 1. ARB extensions, sorted by extension number.
+ 2. Non-ARB extensions, sorted by extension number.
+ 3. Un-numbered extensions, sorted by extension name.
+ """
+
+ try:
+ core_version = float(name)
+ except Exception,e:
+ core_version = 0.0
+
+ if core_version > 0.0:
+ cat_type = 0
+ key = name
+ elif name.startswith("GL_ARB_") or name.startswith("GLX_ARB_") or name.startswith("WGL_ARB_"):
+ cat_type = 1
+ key = int(number)
+ else:
+ if number != None:
+ cat_type = 2
+ key = int(number)
else:
- self.category = c
+ cat_type = 3
+ key = name
+
+ return [cat_type, key]
+
+
+def create_parameter_string(parameters, include_names):
+ """Create a parameter string from a list of gl_parameters."""
+
+ list = []
+ for p in parameters:
+ if include_names:
+ list.append( p.string() )
+ else:
+ list.append( p.type_string() )
+
+ if len(list) == 0: list = ["void"]
+
+ return string.join(list, ", ")
+
+
+class gl_item:
+ def __init__(self, element, context):
+ self.context = context
+ self.name = element.nsProp( "name", None )
+ self.category = real_category_name( element.parent.nsProp( "name", None ) )
return
#if ts == "GLdouble":
# print '/* stack size -> %s = %u (after) */' % (self.name, self.type_expr.get_stack_size())
- self.is_counter = is_attr_true( element, 'counter' )
- self.is_output = is_attr_true( element, 'output' )
+ self.is_client_only = is_attr_true( element, 'client_only' )
+ self.is_counter = is_attr_true( element, 'counter' )
+ self.is_output = is_attr_true( element, 'output' )
# Pixel data has special parameters.
self.return_type = "void"
self.parameters = []
self.offset = -1
- self.uninitialized = 1
+ self.initialized = 0
self.images = []
+ self.assign_offset = 0
+
+ self.static_entry_points = []
+
+ # Track the parameter string (for the function prototype)
+ # for each entry-point. This is done because some functions
+ # change their prototype slightly when promoted from extension
+ # to ARB extension to core. glTexImage3DEXT and glTexImage3D
+ # are good examples of this. Scripts that need to generate
+ # code for these differing aliases need to real prototype
+ # for each entry-point. Otherwise, they may generate code
+ # that won't compile.
+
+ self.parameter_strings = {}
+
self.process_element( element )
return
name = element.nsProp( "name", None )
alias = element.nsProp( "alias", None )
+ if is_attr_true(element, "static_dispatch"):
+ self.static_entry_points.append(name)
+
self.entry_points.append( name )
if alias:
true_name = alias
self.offset = o
except Exception, e:
self.offset = -1
+ if offset == "assign":
+ self.assign_offset = 1
if not self.name:
# There are two possible cases. The first time an entry-point
- # with data is seen, self.uninitialzied will be 1. On that
+ # with data is seen, self.initialized will be 0. On that
# pass, we just fill in the data. The next time an
- # entry-point with data is seen, self.uninitialized will be 0.
+ # entry-point with data is seen, self.initialized will be 1.
# On that pass we have to make that the new values match the
# valuse from the previous entry-point.
+ parameters = []
+ return_type = "void"
child = element.children
- if self.uninitialized:
- while child:
- if child.type == "element":
- if child.name == "return":
- self.return_type = child.nsProp( "type", None )
- elif child.name == "param":
- param = self.context.factory.create_item( "parameter", child, self.context)
- self.parameters.append( param )
-
- child = child.next
- else:
- parameters = []
- while child:
- if child.type == "element":
- if child.name == "return":
- return_type = child.nsProp( "type", None )
- if self.return_type != return_type:
- raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
- elif child.name == "param":
- param = self.context.factory.create_item( "parameter", child, self.context)
- parameters.append( param )
-
- child = child.next
+ while child:
+ if child.type == "element":
+ if child.name == "return":
+ return_type = child.nsProp( "type", None )
+ elif child.name == "param":
+ param = self.context.factory.create_item( "parameter", child, self.context)
+ parameters.append( param )
+
+ child = child.next
+
+
+ if self.initialized:
+ if self.return_type != return_type:
+ raise RuntimeError( "Return type changed in %s. Was %s, now %s." % (name, self.return_type, return_type))
if len(parameters) != len(self.parameters):
raise RuntimeError( "Parameter count mismatch in %s. Was %d, now %d." % (name, len(self.parameters), len(parameters)))
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))
- # This is done becuase we may hit an alias before we
- # hit the "real" entry. The aliases may not have all
- # of the parameter information (e.g., counter,
- # variable_param, etc. fields) required to generate
- # GLX code.
-
- if true_name == name:
- self.parameters = parameters
+ if true_name == name or not self.initialized:
+ self.return_type = return_type
+ self.parameters = parameters
- for param in self.parameters:
- if param.is_image():
- self.images.append( param )
-
- if true_name == name:
for param in self.parameters:
if param.is_image():
self.images.append( param )
if element.children:
- self.uninitialized = 0
+ self.initialized = 1
+ self.parameter_strings[name] = create_parameter_string(parameters, 1)
+ else:
+ self.parameter_strings[name] = None
return
return self.parameters.__iter__();
- def get_parameter_string(self):
- list = []
- for p in self.parameters:
- list.append( p.string() )
+ def get_parameter_string(self, entrypoint = None):
+ if entrypoint:
+ s = self.parameter_strings[ entrypoint ]
+ if s:
+ return s
+
+ return create_parameter_string( self.parameters, 1 )
- if len(list) == 0:
- return "void"
+ def get_called_parameter_string(self):
+ p_string = ""
+ comma = ""
+
+ for p in self.parameterIterator():
+ p_string = p_string + comma + p.name
+ comma = ", "
+
+ return p_string
+
+
+ def is_static_entry_point(self, name):
+ return name in self.static_entry_points
+
+ def dispatch_name(self):
+ if self.name in self.static_entry_points:
+ return self.name
else:
- return string.join(list, ", ")
+ return "_dispatch_stub_%u" % (self.offset)
+
+ def static_name(self, name):
+ if name in self.static_entry_points:
+ return name
+ else:
+ return "_dispatch_stub_%u" % (self.offset)
class gl_item_factory:
self.functions_by_name = {}
self.enums_by_name = {}
self.types_by_name = {}
+
self.category_dict = {}
+ self.categories = [{}, {}, {}, {}]
self.factory = factory
+ self.next_offset = 0
+
typeexpr.create_initial_types()
return
cat_name = cat.nsProp( "name", None )
cat_number = cat.nsProp( "number", None )
+ [cat_type, key] = classify_category(cat_name, cat_number)
+ self.categories[cat_type][key] = [cat_name, cat_number]
+
child = cat.children
while child:
if child.type == "element":
if child.name == "function":
func_name = real_function_name( child )
+ temp_name = child.nsProp( "name", None )
+ self.category_dict[ temp_name ] = [cat_name, cat_number]
+
if self.functions_by_name.has_key( func_name ):
func = self.functions_by_name[ func_name ]
func.process_element( child )
func = self.factory.create_item( "function", child, self )
self.functions_by_name[ func_name ] = func
- if func_name == child.nsProp("name", None):
- self.category_dict[ func.name ] = [cat_name, cat_number]
+ if func.offset >= self.next_offset:
+ self.next_offset = func.offset + 1
+
elif child.name == "enum":
enum = self.factory.create_item( "enum", child, self )
return
+ def functionIterateByCategory(self, cat = None):
+ """Iterate over functions by category.
+
+ If cat is None, all known functions are iterated in category
+ order. See classify_category for details of the ordering.
+ Within a category, functions are sorted by name. If cat is
+ not None, then only functions in that category are iterated.
+ """
+ lists = [{}, {}, {}, {}]
+
+ for func in self.functionIterateAll():
+ [cat_name, cat_number] = self.category_dict[func.name]
+
+ if (cat == None) or (cat == cat_name):
+ [func_cat_type, key] = classify_category(cat_name, cat_number)
+
+ if not lists[func_cat_type].has_key(key):
+ lists[func_cat_type][key] = {}
+
+ lists[func_cat_type][key][func.name] = func
+
+
+ functions = []
+ for func_cat_type in range(0,4):
+ keys = lists[func_cat_type].keys()
+ keys.sort()
+
+ for key in keys:
+ names = lists[func_cat_type][key].keys()
+ names.sort()
+
+ for name in names:
+ functions.append(lists[func_cat_type][key][name])
+
+ return functions.__iter__()
+
+
def functionIterateByOffset(self):
max_offset = -1
for func in self.functions_by_name.itervalues():
return list.__iter__()
+ def categoryIterate(self):
+ """Iterate over categories.
+
+ Iterate over all known categories in the order specified by
+ classify_category. Each iterated value is a tuple of the
+ name and number (which may be None) of the category.
+ """
+
+ list = []
+ for cat_type in range(0,4):
+ keys = self.categories[cat_type].keys()
+ keys.sort()
+
+ for key in keys:
+ list.append(self.categories[cat_type][key])
+
+ return list.__iter__()
+
+
def get_category_for_name( self, name ):
if self.category_dict.has_key(name):
return self.category_dict[name]