+ def __init__(self, element, context):
+ self.context = context
+ self.name = None
+
+ self.entry_points = []
+ self.return_type = "void"
+ self.parameters = []
+ self.offset = -1
+ self.initialized = 0
+ self.images = []
+ self.exec_flavor = 'mesa'
+ self.desktop = True
+ self.deprecated = None
+
+ # self.entry_point_api_map[name][api] is a decimal value
+ # indicating the earliest version of the given API in which
+ # each entry point exists. Every entry point is included in
+ # the first level of the map; the second level of the map only
+ # lists APIs which contain the entry point in at least one
+ # version. For example,
+ # self.entry_point_api_map['ClipPlanex'] == { 'es1':
+ # Decimal('1.1') }.
+ self.entry_point_api_map = {}
+
+ # self.api_map[api] is a decimal value indicating the earliest
+ # version of the given API in which ANY alias for the function
+ # exists. The map only lists APIs which contain the function
+ # in at least one version. For example, for the ClipPlanex
+ # function, self.entry_point_api_map == { 'es1':
+ # Decimal('1.1') }.
+ self.api_map = {}
+
+ 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.entry_point_parameters = {}
+
+ self.process_element( element )
+
+ return
+
+
+ def process_element(self, element):
+ name = element.get( "name" )
+ alias = element.get( "alias" )
+
+ if is_attr_true(element, "static_dispatch", "true"):
+ self.static_entry_points.append(name)
+
+ self.entry_points.append( name )
+
+ self.entry_point_api_map[name] = {}
+ for api in ('es1', 'es2'):
+ version_str = element.get(api, 'none')
+ assert version_str is not None
+ if version_str != 'none':
+ version_decimal = Decimal(version_str)
+ self.entry_point_api_map[name][api] = version_decimal
+ if api not in self.api_map or \
+ version_decimal < self.api_map[api]:
+ self.api_map[api] = version_decimal
+
+ exec_flavor = element.get('exec')
+ if exec_flavor:
+ self.exec_flavor = exec_flavor
+
+ deprecated = element.get('deprecated', 'none')
+ if deprecated != 'none':
+ self.deprecated = Decimal(deprecated)
+
+ if not is_attr_true(element, 'desktop', 'true'):
+ self.desktop = False
+
+ if alias:
+ true_name = alias
+ else:
+ true_name = name
+
+ # Only try to set the offset when a non-alias entry-point
+ # is being processed.
+
+ offset = element.get( "offset" )
+ if offset:
+ try:
+ o = int( offset )
+ self.offset = o
+ except Exception, e:
+ self.offset = -1
+ if offset == "assign":
+ self.assign_offset = 1
+
+
+ if not self.name:
+ self.name = true_name
+ elif self.name != true_name:
+ raise RuntimeError("Function true name redefined. Was %s, now %s." % (self.name, true_name))
+
+
+ # There are two possible cases. The first time an entry-point
+ # 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.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"
+ for child in element.getchildren():
+ if child.tag == "return":
+ return_type = child.get( "type", "void" )
+ elif child.tag == "param":
+ param = self.context.factory.create_parameter(child, self.context)
+ parameters.append( param )
+
+
+ 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)))
+
+ for j in range(0, len(parameters)):
+ p1 = parameters[j]
+ p2 = self.parameters[j]
+ if not p1.compatible( p2 ):
+ 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))
+
+
+ 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 element.getchildren():
+ self.initialized = 1
+ self.entry_point_parameters[name] = parameters
+ else:
+ self.entry_point_parameters[name] = []
+
+ return
+
+ def filter_entry_points(self, entry_point_list):
+ """Filter out entry points not in entry_point_list."""
+ if not self.initialized:
+ raise RuntimeError('%s is not initialized yet' % self.name)
+
+ entry_points = []
+ for ent in self.entry_points:
+ if ent not in entry_point_list:
+ if ent in self.static_entry_points:
+ self.static_entry_points.remove(ent)
+ self.entry_point_parameters.pop(ent)
+ else:
+ entry_points.append(ent)
+
+ if not entry_points:
+ raise RuntimeError('%s has no entry point after filtering' % self.name)
+
+ self.entry_points = entry_points
+ if self.name not in entry_points:
+ # use the first remaining entry point
+ self.name = entry_points[0]
+ self.parameters = self.entry_point_parameters[entry_points[0]]
+
+ def get_images(self):
+ """Return potentially empty list of input images."""
+ return self.images
+
+
+ def parameterIterator(self, name = None):
+ if name is not None:
+ return self.entry_point_parameters[name].__iter__();
+ else:
+ return self.parameters.__iter__();
+
+
+ def get_parameter_string(self, entrypoint = None):
+ if entrypoint:
+ params = self.entry_point_parameters[ entrypoint ]
+ else:
+ params = self.parameters
+
+ return create_parameter_string( params, 1 )
+
+ def get_called_parameter_string(self):
+ p_string = ""
+ comma = ""
+
+ for p in self.parameterIterator():
+ if p.is_padding:
+ continue
+ p_string = p_string + comma + p.name
+ comma = ", "
+
+ return p_string
+
+
+ def is_abi(self):
+ return (self.offset >= 0 and not self.assign_offset)
+
+ 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 "_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)