X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=scripts%2Fextgen.py;h=4c3565e82cc0ac4ded23b39fbef6028d1978c27d;hp=f5df83f21588ab0cbb71f94d8a94a8d05023af7a;hb=587b88ea9730cee089428b6491b9b166a1793173;hpb=137b642f43f175a98a45b95de5b0735c5c487a2e diff --git a/scripts/extgen.py b/scripts/extgen.py index f5df83f2..4c3565e8 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) @@ -338,22 +325,35 @@ class GlXmlParser: def detect_core_version(host_api, things): - candidates = {} + 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 +398,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): things_by_ext = {} for t in things: exts = [] @@ -408,37 +412,63 @@ 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 + extensions = [] + missing = set(things) + while missing and things_by_ext: + 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 + elif count==largest_count and e.preference>largest_ext.preference: + largest_ext = e + + extensions.append(largest_ext) + for t in things_by_ext[largest_ext]: + missing.remove(t) + if not missing: + break + + 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 missing: + return None - return largest_ext + return extensions class SourceGenerator: - def __init__(self, host_api, target_ext, things): + def __init__(self, host_api, ext_name, things, optional_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.ext_name = ext_name + all_things = things+optional_things + self.funcs = filter((lambda t: t.kind==Thing.FUNCTION), all_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 = filter((lambda t: t.kind==Thing.ENUM), all_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) + self.backport_ext = detect_backport_extension(host_api, things); + self.source_exts = detect_source_extension(host_api, things) + + if not self.core_version and not self.backport_ext and not self.source_exts: + print "Warning: Not supportable on host API" 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("#ifndef MSP_GL_%s_\n"%self.ext_name.upper()) + out.write("#define MSP_GL_%s_\n"%self.ext_name.upper()) out.write(""" #include @@ -486,7 +516,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 +542,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: @@ -524,34 +554,32 @@ namespace GL { out.write(", %r"%self.deprecated_version) out.write("))\n\t{\n") for f in self.funcs: - supp = f.api_support.get(self.host_api.name) - if supp: - gpa_suffix = "" - if supp.core_version is not None and supp.core_version<=Version(1, 1): - gpa_suffix = "_1_1" - out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS%s(%s));\n"%(f.name, self.func_typedefs[f.name], gpa_suffix, f.name)) + supp = f.api_support[self.host_api.name] + gpa_suffix = "" + if supp.core_version is not None and supp.core_version<=Version(1, 1): + gpa_suffix = "_1_1" + out.write("\t\t%s = reinterpret_cast<%s>(GET_PROC_ADDRESS%s(%s));\n"%(f.name, self.func_typedefs[f.name], gpa_suffix, f.name)) 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(%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: + supp = f.api_support[self.host_api.name] + if supp.sources: src = None - for s in supp.sources: - if s.name.endswith(self.source_ext.ext_type): - src = s + for e in self.source_exts: + for s in supp.sources: + if s.name in e.things: + src = s + break + if src: 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) + 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 +598,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,8 +606,7 @@ 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) @@ -589,9 +616,9 @@ class ExtensionParser: self.target_ext = None self.core_version = None self.deprecated_version = None - self.secondary_exts = [] self.backport_ext = None self.ignore_things = [] + self.optional_things = [] def parse(self, fn): for line in open(fn): @@ -600,56 +627,64 @@ class ExtensionParser: 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=="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,7 +695,7 @@ 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) + sys.exit(1) host_api_name = "gl" @@ -670,7 +705,8 @@ replaced with cpp and h.""" 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