+ common_things = ext_things_by_api.get("", [])
+ supported = ext.getAttribute("supported").split('|')
+ for s in supported:
+ api = self.apis.get(s)
+ if not api:
+ continue
+
+ ext = get_or_create(api.extensions, ext_name, Extension, api)
+ api_things = ext_things_by_api.get(s, [])
+ for t in itertools.chain(common_things, api_things):
+ ext.things[t.name] = t
+ t.get_or_create_api_support(api.name).extensions.append(ext)
+
+ def parse_file(self, fn):
+ doc = xml.dom.minidom.parse(fn)
+ root = doc.documentElement
+
+ commands = get_nested_elements(root, "commands/command")
+ for cmd in commands:
+ self.parse_command(cmd)
+
+ enums = get_nested_elements(root, "enums/enum")
+ for en in enums:
+ self.parse_enum(en)
+
+ features = get_nested_elements(root, "feature")
+ for feat in features:
+ self.parse_feature(feat)
+
+ extensions = get_nested_elements(root, "extensions/extension")
+ for ext in extensions:
+ self.parse_extension(ext)
+
+ def check_backport_extensions(self, api):
+ for e in api.extensions.itervalues():
+ e.backport = True
+ for t in e.things.itervalues():
+ if t.name.endswith(e.ext_type):
+ e.backport = False
+ break
+
+ def resolve_enum_aliases(self, api):
+ core_enums = filter((lambda t: t.kind==Thing.ENUM), api.core_things.itervalues())
+ core_enums_by_value = dict((e.value, None) for e in core_enums)
+
+ for e in api.extensions.itervalues():
+ ext_enums = filter((lambda t: t.kind==Thing.ENUM), e.things.itervalues())
+ enum_suffix = "_"+e.ext_type
+ for n in ext_enums:
+ if n.api_support[api.name].core_version:
+ continue
+
+ name = n.name
+ if name.endswith(enum_suffix):
+ name = name[:-len(enum_suffix)]
+ ce = api.core_things.get(name)
+ if not ce and n.value in core_enums_by_value:
+ if core_enums_by_value[n.value] is None:
+ core_enums_by_value[n.value] = filter((lambda e: e.value==n.value), core_enums)
+ for c in core_enums_by_value[n.value]:
+ if c.bitmask==n.bitmask:
+ ce = c
+ break
+ if ce and ce.value==n.value and ce.name not in n.aliases:
+ n.aliases.append(ce.name)
+
+ def resolve_sources(self, api):
+ for e in api.extensions.itervalues():
+ for t in e.things.itervalues():
+ for a in t.aliases:
+ # There are a few cases where a vendor function is aliased to
+ # an EXT or ARB function but those are rare and not relevant for
+ # our use
+ alias = api.core_things.get(a)
+ if alias:
+ sources = alias.api_support[api.name].sources
+ if t not in sources:
+ sources.append(t)
+
+ def sort_extensions(self):
+ for a in self.apis.itervalues():
+ e = a.extensions.get(self.target_ext_name)
+ if e:
+ e.preference = 3
+ for t in self.things.itervalues():
+ for s in t.api_support.itervalues():
+ s.extensions.sort(key=(lambda e: e.preference), reverse=True)
+
+ def finalize(self):
+ for a in self.apis.itervalues():
+ self.check_backport_extensions(a)
+ self.resolve_enum_aliases(a)
+ self.resolve_sources(a)
+ self.sort_extensions()
+
+
+def detect_core_version(host_api, things):
+ candidates = {}
+ for t in things:
+ supp = t.api_support.get(host_api.name)
+ if supp and supp.core_version:
+ candidates[supp.core_version] = candidates.get(supp.core_version, 0)+1
+
+ if candidates:
+ candidates = list((v, k) for k, v in candidates.items())
+ if len(candidates)>1:
+ candidates.sort(reverse=True)
+ if candidates[1][0]+1>=candidates[0][0]:
+ print "Warning: multiple likely core version candidates: %s %s"%(candidates[0][1], candidates[1][1])
+ return candidates[0][1]
+
+def detect_deprecated_version(host_api, things):
+ min_version = None
+ for t in things:
+ supp = t.api_support.get(host_api.name)
+ if supp and supp.deprecated_version:
+ if min_version is None:
+ min_version = supp.deprecated_version
+ else:
+ min_version = min(min_version, supp.deprecated_version)
+ else:
+ return None
+
+ return min_version
+
+def detect_backport_extension(host_api, target_ext, things):
+ candidates = []
+ for t in things:
+ supp = t.api_support.get(host_api.name)
+ if supp and supp.core_version:
+ for e in supp.extensions:
+ if e.backport and e not in candidates:
+ candidates.append(e)
+
+ if len(candidates)>1:
+ print "Warning: multiple backport extension candidates: %s"%(" ".join(e.name for e in candidates))
+
+ for e in candidates:
+ if e.base_name==target_ext.base_name:
+ return e
+
+ if len(candidates)==1:
+ print "Warning: potential backport extension has mismatched name: %s"%candidates[0].name
+
+def collect_extensions(thing, api, exts):
+ supp = thing.api_support.get(api)
+ if not supp:
+ return
+
+ for e in supp.extensions:
+ if not e.backport and e not in exts:
+ exts.append(e)
+
+ for s in supp.sources:
+ collect_extensions(s, api, exts)
+
+def detect_source_extension(host_api, target_ext, things):
+ if target_ext.name in host_api.extensions:
+ return target_ext
+
+ things_by_ext = {}
+ for t in things:
+ exts = []
+ collect_extensions(t, host_api.name, exts)
+ for e in exts:
+ things_by_ext.setdefault(e, []).append(t)
+
+ largest_ext = None
+ largest_count = 0
+ for e, t in things_by_ext.iteritems():
+ count = len(t)
+ if count>largest_count:
+ largest_ext = e
+ largest_count = count
+
+ return largest_ext
+
+
+class SourceGenerator:
+ def __init__(self, host_api, target_ext, things):
+ self.host_api = host_api
+ self.api_prefix = "GL"
+ if self.host_api.name=="gles2":
+ self.api_prefix = "GL_ES"
+ self.target_ext = target_ext
+ self.funcs = filter((lambda t: t.kind==Thing.FUNCTION), things)
+ self.funcs.sort(key=(lambda f: f.name))
+ self.func_typedefs = dict((f.name, "FPtr_"+f.name) for f in self.funcs)
+ self.enums = filter((lambda t: t.kind==Thing.ENUM), things)
+ self.enums.sort(key=(lambda e: e.value))
+ self.core_version = detect_core_version(host_api, things)
+ self.deprecated_version = detect_deprecated_version(host_api, things)
+ self.backport_ext = detect_backport_extension(host_api, target_ext, things);
+ self.source_ext = detect_source_extension(host_api, target_ext, things)
+
+ def write_header_intro(self, out):
+ out.write("#ifndef MSP_GL_%s_\n"%self.target_ext.name.upper())
+ out.write("#define MSP_GL_%s_\n"%self.target_ext.name.upper())
+
+ out.write("""