X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=scripts%2Fextgen.py;h=92c78b504ff5a27ae1582c0e5d294f748d3692ed;hp=f5df83f21588ab0cbb71f94d8a94a8d05023af7a;hb=9d1fa012a23693768bbe287371e97751c03acc50;hpb=137b642f43f175a98a45b95de5b0735c5c487a2e diff --git a/scripts/extgen.py b/scripts/extgen.py index f5df83f2..92c78b50 100755 --- a/scripts/extgen.py +++ b/scripts/extgen.py @@ -43,6 +43,12 @@ class Version: return self.major>other.major return self.minor>other.minor + def __eq__(self, other): + if other is None: + return False + + return (self.major==other.major and self.minor==other.minor) + class Thing: FUNCTION = 1 @@ -145,9 +151,7 @@ def get_or_create(map, name, type, *args): class GlXmlParser: - def __init__(self, host_api_name, target_ext_name): - self.host_api_name = host_api_name - self.target_ext_name = target_ext_name + def __init__(self): self.apis = {} self.things = {} @@ -177,10 +181,12 @@ class GlXmlParser: enum.value = int(en.getAttribute("value"), 16) + alias = en.getAttribute("alias") + if alias: + enum.aliases.append(alias) + def parse_feature(self, feat): api_name = feat.getAttribute("api") - if not api_name: - api_name = self.host_api_name api = get_or_create(self.apis, api_name, Api) version = feat.getAttribute("number") @@ -204,7 +210,6 @@ class GlXmlParser: removes = get_nested_elements(feat, "remove") for rem in removes: - profile = rem.getAttribute("profile") commands = get_nested_elements(rem, "command") enums = get_nested_elements(rem, "enum") @@ -212,15 +217,8 @@ class GlXmlParser: name = t.getAttribute("name") thing = self.things.get(name) if thing: - if profile!="core": - if thing.name in api.core_things: - del api.core_things[thing.name] - for s in thing.api_support.itervalues(): - for e in s.extensions: - del e.things[thing.name] - else: - supp = thing.get_or_create_api_support(api.name) - supp.deprecated_version = version + supp = thing.get_or_create_api_support(api.name) + supp.deprecated_version = version def parse_extension(self, ext): ext_things_by_api = {} @@ -276,6 +274,9 @@ class GlXmlParser: def check_backport_extensions(self, api): for e in api.extensions.itervalues(): + if e.ext_type!="ARB": + continue + e.backport = True for t in e.things.itervalues(): if t.name.endswith(e.ext_type): @@ -283,9 +284,6 @@ class GlXmlParser: 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 @@ -297,13 +295,6 @@ class GlXmlParser: 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) @@ -321,10 +312,6 @@ class GlXmlParser: 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) @@ -337,23 +324,41 @@ class GlXmlParser: self.sort_extensions() -def detect_core_version(host_api, things): - candidates = {} +def detect_core_version(host_api, things, debug=None): + max_version = Version(1, 0) + max_count = 0 + lower_count = 0 + missing = [] 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 supp.core_version>max_version: + max_version = supp.core_version + lower_count += max_count + max_count = 1 + elif supp.core_version==max_version: + max_count += 1 + else: + lower_count += 1 + else: + missing.append(t) - 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] + if lower_count>max_count or (missing and len(missing)*21: - print "Warning: multiple backport extension candidates: %s"%(" ".join(e.name for e in candidates)) - + total_count = len(things) + best_ext = None + best_count = 0 for e in candidates: - if e.base_name==target_ext.base_name: + things_in_ext = filter((lambda t: t.name in e.things), things) + count = len(things_in_ext) + if count==total_count: return e + elif count>best_count: + best_ext = e + best_count = count - if len(candidates)==1: - print "Warning: potential backport extension has mismatched name: %s"%candidates[0].name + if best_count*2>=total_count: + print "Warning: Inconsistent backport extension %s"%best_ext.name def collect_extensions(thing, api, exts): supp = thing.api_support.get(api) @@ -391,16 +408,13 @@ def collect_extensions(thing, api, exts): return for e in supp.extensions: - if not e.backport and e not in exts: + if not e.backport and e.ext_type!="MSP" 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 - +def detect_source_extension(host_api, things, debug=False): things_by_ext = {} for t in things: exts = [] @@ -408,37 +422,122 @@ def detect_source_extension(host_api, target_ext, things): 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 + if debug: + print "---" + print "Looking for %d things in %d extensions"%(len(things), len(things_by_ext)) + + extensions = [] + keep_exts = 0 + base_version = None + recheck_base_version = True + missing = set(things) + while 1: + if recheck_base_version: + max_version = Version(1, 0) + for t in missing: + supp = t.api_support.get(host_api.name) + if supp and supp.core_version and max_version: + max_version = max(max_version, supp.core_version) + else: + max_version = None + + if max_version: + if not base_version or max_versionlargest_count: + largest_ext = e + largest_count = count + elif count==largest_count and e.preference>largest_ext.preference: + largest_ext = e + + if debug: + print "Found %d things in %s"%(largest_count, largest_ext.name) + + extensions.append(largest_ext) + for t in things_by_ext[largest_ext]: + missing.remove(t) + + supp = t.api_support.get(host_api.name) + if supp and supp.core_version==base_version: + recheck_base_version = True + + del things_by_ext[largest_ext] + for e in things_by_ext.keys(): + unseen = filter((lambda t: t in missing), things_by_ext[e]) + if unseen: + things_by_ext[e] = unseen + else: + del things_by_ext[e] + + if not missing: + return None, extensions + elif base_version: + if debug: + print "Found remaining things in version %s"%base_version + if keep_exts @@ -486,7 +585,7 @@ namespace GL { """) def write_source_intro(self, out): - out.write("#include \"%s.h\"\n"%self.target_ext.name.lower()) + out.write("#include \"%s.h\"\n"%self.ext_name.lower()) if self.funcs: out.write(""" #ifdef __APPLE__ @@ -512,9 +611,9 @@ namespace GL { out.write("%s %s = 0;\n"%(self.func_typedefs[f.name], f.name)) def write_init_function(self, out): - out.write("\nExtension::SupportLevel init_%s()\n{\n"%self.target_ext.name.lower()) + out.write("\nExtension::SupportLevel init_%s()\n{\n"%self.ext_name.lower()) if self.core_version: - out.write("\tif(is_disabled(\"GL_%s\"))\n\t\treturn Extension::UNSUPPORTED;\n"%self.target_ext.name) + out.write("\tif(is_disabled(\"GL_%s\"))\n\t\treturn Extension::UNSUPPORTED;\n"%self.ext_name) out.write("#if !defined(__APPLE__) || defined(%s_%s)\n"%(self.api_prefix, self.core_version.as_define())) out.write("\tif(") if self.backport_ext: @@ -533,25 +632,29 @@ namespace GL { out.write("\t\treturn Extension::CORE;\n") out.write("\t}\n") out.write("#endif\n") - if self.source_ext and self.source_ext!=self.backport_ext: - out.write("#if !defined(__APPLE__) || defined(GL_%s)\n"%self.target_ext.name) - out.write("\tif(is_supported(\"GL_%s\"))\n\t{\n"%(self.source_ext.name)) + if self.source_exts: + out.write("#if !defined(__APPLE__) || defined(GL_%s)\n"%self.ext_name) + out.write("\tif(") + if self.base_version: + out.write("is_supported(%r) && "%self.base_version) + out.write("%s)\n\t{\n"%" && ".join("is_supported(\"GL_%s\")"%s.name for s in self.source_exts)) for f in self.funcs: supp = f.api_support.get(self.host_api.name) - if supp and supp.sources: - src = None - for s in supp.sources: - if s.name.endswith(self.source_ext.ext_type): - src = s - break - if not src: - src = supp.sources[0] - else: - src = f - - if self.host_api.name in src.api_support: - if not src.name.endswith(self.source_ext.ext_type): - print "Warning: %s does not match extension type %s"%(src.name, self.source_ext.ext_type) + src = None + for e in self.source_exts: + if f.name in e.things: + src = f + elif supp: + for s in supp.sources: + if s.name in e.things: + src = s + break + if src: + break + if not src and supp and supp.core_version and self.base_version>=supp.core_version: + sec = f + + if src: out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS(%s));\n"%(f.name, self.func_typedefs[f.name], src.name)) out.write("\t\treturn Extension::EXTENSION;\n") out.write("\t}\n") @@ -570,7 +673,7 @@ namespace GL { self.write_header_intro(out) self.write_enum_definitions(out) self.write_function_pointer_declarations(out) - out.write("extern Extension %s;\n"%self.target_ext.name) + out.write("extern Extension %s;\n"%self.ext_name) self.write_header_outro(out) def write_source(self, fn): @@ -578,78 +681,111 @@ namespace GL { self.write_source_intro(out) self.write_function_pointer_definitions(out) self.write_init_function(out) - ext_name = self.target_ext.name - out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(ext_name, ext_name, ext_name.lower())) + out.write("\nExtension %s(\"GL_%s\", init_%s);\n"%(self.ext_name, self.ext_name, self.ext_name.lower())) self.write_source_outro(out) +def dump_api_support(supp, api, indent): + if supp.core_version: + print indent+"core in version "+str(supp.core_version) + if supp.deprecated_version: + print indent+"deprecated in version "+str(supp.deprecated_version) + for e in supp.extensions: + print indent+"extension %s (preference %d)"%(e.name, e.preference) + for r in supp.sources: + print indent+"source "+r.name + dump_thing_info(r, api, indent+" ") + +def dump_thing_info(thing, api, indent): + for a in thing.aliases: + print indent+"alias "+a + if api: + supp = thing.api_support.get(api) + dump_api_support(supp, api, indent) + else: + for a, s in thing.api_support.iteritems(): + print indent+"api "+a + dump_api_support(s, a, indent+" ") + + class ExtensionParser: def __init__(self, host_api): self.host_api = host_api self.target_ext = None self.core_version = None self.deprecated_version = None - self.secondary_exts = [] self.backport_ext = None + self.source_exts = [] self.ignore_things = [] + self.optional_things = [] def parse(self, fn): for line in open(fn): line = line.strip() - if line.startswith("#"): + if not line or line.startswith("#"): continue parts = line.split() + api = None keyword = parts[0] + if ":" in keyword: + api, keyword = keyword.split(":") + + if api is not None and api!=self.host_api: + continue if keyword=="extension": self.target_ext = parts[1] elif keyword=="core_version": - if parts[1]==self.host_api: - self.core_version = Version(*map(int, parts[2].split('.'))) + self.core_version = Version(*map(int, parts[1].split('.'))) elif keyword=="deprecated": - if parts[1]==self.host_api: - self.deprecated_version = Version(*map(int, parts[2].split('.'))) - elif keyword=="secondary": - self.secondary_exts.append(parts[1]) + self.deprecated_version = Version(*map(int, parts[1].split('.'))) elif keyword=="backport": self.backport_ext = parts[1] + elif keyword=="source": + self.source_exts.append(parts[1]) elif keyword=="ignore": self.ignore_things.append(parts[1]) + elif keyword=="optional": + self.optional_things.append(parts[1]) + else: + print "Unknown keyword "+keyword + return False + + return True def get_extension(api_map, ext_name): - main_api = api_map["gl"] - ext = main_api.extensions.get(ext_name) - if ext: - return ext + if "." in ext_name: + ext_api_name, ext_name = ext_name.split(".") + else: + ext_api_name = "gl" + + return api_map[ext_api_name].extensions[ext_name] + +def resolve_things(api, things): + rthings = [] + for t in things: + ct = filter(None, map(api.core_things.get, t.aliases)) + if ct: + rthings += ct + else: + rthings.append(t) - for a in api_map.itervalues(): - ext = a.extensions.get(ext_name) - if ext: - return ext + return rthings -def collect_things(host_api, target_ext, secondary, ignore): +def collect_extension_things(host_api, target_ext, ignore): ext_things = [t for n, t in target_ext.things.iteritems() if n not in ignore] - core_things = target_ext.api.core_things + return resolve_things(target_ext.api, ext_things) +def collect_optional_things(target_ext, names): things = [] - for t in ext_things: - found_in_core = False - for a in t.aliases: - if a in core_things: - things.append(core_things[a]) - found_in_core = True - if not found_in_core: - things.append(t) - - for s in secondary: - for t in s.things.itervalues(): - for a in t.aliases: - if a in core_things and core_things[a] not in things: - things.append(core_things[a]) - - return things + for t in names: + if t in target_ext.things: + things.append(target_ext.things[t]) + else: + things.append(target_ext.api.core_things[t]) + return resolve_things(target_ext.api, things) def main(): if len(sys.argv)<2: @@ -660,17 +796,23 @@ Reads gl.xml and generates C++ source files to use an OpenGL extension described in . If is absent, the extension's lowercased name is used. Anything after the last dot in is removed and replaced with cpp and h.""" - sys.exit(0) - - host_api_name = "gl" + sys.exit(1) i = 1 + + debug = False + if sys.argv[i]=="-g": + debug = True + i += 1 + + host_api_name = "gl" if sys.argv[i].startswith("gl"): host_api_name = sys.argv[i] i += 1 ext_parser = ExtensionParser(host_api_name) - ext_parser.parse(sys.argv[i]) + if not ext_parser.parse(sys.argv[i]): + sys.exit(1) i += 1 if i